home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / AppsToGo / DTS.Lib / TextEditControl.c < prev    next >
Encoding:
Text File  |  1994-09-22  |  80.3 KB  |  3,174 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         texteditcontrol.c
  5. ** Written by:      Eric Soldan
  6. ** Based on:        TESample, by Bryan Stearns
  7. ** Suggestions by:  Forrest Tanaka, Dave Radcliffe
  8. **
  9. ** Copyright © 1990-1993 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21. /* This is a control implementation of TextEdit.  The advantages to this are:
  22. **
  23. ** 1) Makes using TextEdit in a non-dialog window easy.
  24. ** 2) The TextEdit record is automatically associated with the window, since
  25. **    it is in the window's control list.
  26. ** 3) The TextEdit control can have scrollbars associated with it, and these
  27. **    are also kept in the window's control list.
  28. ** 4) Updating of the TextEdit record is much simpler, since all that is
  29. **    necessary is to draw the control (or all the window's controls with
  30. **    a DrawControls call).
  31. ** 5) There are simple calls to handle TextEdit events.
  32. ** 6) Undo is already supported.
  33. ** 7) A document length can be specified.  This length will not be exceeded
  34. **    when editing the TextEdit record.
  35. ** 8) When you close the window, the TextEdit record is disposed of.
  36. **    (This automatic disposal can easily be defeated.)
  37. **
  38. **
  39. ** To create a TextEdit control, you only need a single call.  For example:
  40. **
  41. **    CTENew(rViewCtl,            Resource ID of view control for TextEdit control.
  42. **           true,                 Control initially visible.
  43. **           window,                Window to hold TERecord.
  44. **           &teHndl,                Return handle for TERecord.
  45. **           &ctlRct,                Rect for TextEdit view control.
  46. **           &destRct,            destRct for TERecord
  47. **           &viewRct,            viewRct for TERecord
  48. **           &borderRct,            Used to frame a border.
  49. **           32000,                Max size for TERecord text.
  50. **           cteVScrollLessGrow    TERecord read-write, with vertical scroll
  51. **                                that leaves space for grow box.
  52. **    );
  53. **
  54. ** If you create a TextEdit control that is read-only, you will not be able
  55. ** to edit it, of course.  There will also be no blinking caret for that
  56. ** TextEdit control.  You will be able to select text and copy to the
  57. ** clipboard, but that is all.
  58.  
  59. ** Simply create destRct, viewRct, and borderRct appropriately, and
  60. ** then call CTENew (which stands for Control TENew).  If teHndl is returned
  61. ** nil, then CTENew failed.  Otherwise, you now have a TextEdit control in
  62. ** the window.
  63. **
  64. ** NOTE: There is a TextEdit bug (no way!!) such that you may need to set the
  65. **       viewRct right edge 2 bigger than the right edge of destRct.  If you
  66. **       do not do this, then there will be some clipping on the right edge in
  67. **       some cases.  Of course, you may want this.  You may want horizontal
  68. **       scrolling, and therefore you would want the destRct substantially
  69. **       larger than the viewRct.  If you don't want horizontal scrolling,
  70. **       then you probably don't want any clipping horizontally, and therefore
  71. **       you will need to set destRct.right 2 less than viewRct.right.
  72. **
  73. **
  74. ** If the CTENew call succeeds, you then have a TextEdit control in your
  75. ** window.  It will be automatically disposed of when you close the window.
  76. ** If you don't waht this to happen, then you can detach it from the
  77. ** view control which owns it.  To do this, you would to the following:
  78. **
  79. **  viewCtl = CTEViewFromTE(theTextEditHndl);
  80. **  if (viewCtl) SetControlReference(viewCtl, nil);
  81. **
  82. ** The view control keeps a reference to the TextEdit record in the refCon.
  83. ** If the refCon is cleared, then the view control does nothing.  So, all that
  84. ** is needed to detach a TextEdit record from a view control is to set the
  85. ** view control's refCon nil.  Now if you close the window, you will still
  86. ** have the TextEdit record.
  87. **
  88. **
  89. ** To remove a TextEdit control completely from a window, you make one call:
  90. **
  91. **  CTEDispose(theTextEditHndl);
  92. **
  93. ** This disposes of the TextEdit record, the view control, and any scrollbar
  94. ** controls that were created when the TextEdit control was created with
  95. ** the call CTENew.
  96. **
  97. **
  98. ** Events for TextEdit record are handled nearly automatically.  You can
  99. ** make one of 3 calls:
  100. **
  101. **  CTEClick(window, eventPtr, &action);
  102. **  CTEEvent(window, eventPtr, &action);
  103. **  CTEKey(window, eventPtr);
  104. **
  105. ** In each case, if the event was handled, true is returned.  CTEEvent simply
  106. ** calls either CTEClick or CTEKey, whichever is appropriate.
  107. **
  108. **
  109. ** Another call you will want to use is CTEEditMenu.  This is used to set the
  110. ** state of cut/copy/paste/clear for TextEdit controls.  It checks the active
  111. ** control to see if text is selected, if the control is read-only, etc.
  112. ** Based on this information, it sets cut/copy/paste/clear either active
  113. ** or inactive.  If any menu items are set active, it returns true.
  114. **
  115. **
  116. ** One more high-level call is CTEUndo().  In response to an undo menu item
  117. ** being selected by the user, just call CTEUndo(), and the edits the user
  118. ** has made will be undone.  (This includes undoing an undo.)
  119. **
  120. **
  121. ** The last high-level call is CTEClipboard.  Call it when you want to do a
  122. ** cut/copy/paste/clear for the active TextEdit control.  The value to pass
  123. ** is as follows:
  124. **
  125. **  2: cut
  126. **  3: copy
  127. **  4: paste
  128. **  5: clear
  129. **
  130. ** These are the same values you would pass to a DA for these actions.
  131. */
  132.  
  133.  
  134.  
  135. /*****************************************************************************/
  136.  
  137.  
  138.  
  139. #ifndef __TEXTEDITCONTROL__
  140. #include "TextEditControl.h"
  141. #endif
  142.  
  143. #ifndef __BALLOONS__
  144. #include <Balloons.h>
  145. #endif
  146.  
  147. #ifndef __CONTROLS__
  148. #include <Controls.h>
  149. #endif
  150.  
  151. #ifndef __DTSLib__
  152. #include "DTS.Lib.h"
  153. #endif
  154.  
  155. #ifndef __ERRORS__
  156. #include <Errors.h>
  157. #endif
  158.  
  159. #ifndef __EVENTS__
  160. #include <Events.h>
  161. #endif
  162.  
  163. #ifndef __FONTS__
  164. #include <Fonts.h>
  165. #endif
  166.  
  167. #ifndef __GESTALTEQU__
  168. #include <GestaltEqu.h>
  169. #endif
  170.  
  171. #ifndef __MEMORY__
  172. #include <Memory.h>
  173. #endif
  174.  
  175. #ifndef __MENUS__
  176. #include <Menus.h>
  177. #endif
  178.  
  179. #ifndef __OSEVENTS__
  180. #include <OSEvents.h>
  181. #endif
  182.  
  183. #ifndef __OSUTILS__
  184. #include <OSUtils.h>
  185. #endif
  186.  
  187. #ifndef __RESOURCES__
  188. #include <Resources.h>
  189. #endif
  190.  
  191. #ifndef __SCRAP__
  192. #include <Scrap.h>
  193. #endif
  194.  
  195. #ifndef __SCRIPT__
  196. #include <Script.h>
  197. #endif
  198.  
  199. #ifndef __TEXTSERVICES__
  200. #include <TextServices.h>
  201. #endif
  202.  
  203. #ifndef __TSMTE__
  204. #include <TSMTE.h>
  205. #endif
  206.  
  207. #ifndef __UTILITIES__
  208. #include "Utilities.h"
  209. #endif
  210.  
  211.  
  212.  
  213. /*****************************************************************************/
  214.  
  215. #ifdef powerc
  216. #pragma options align=mac68k
  217. #endif
  218. typedef struct cdefRsrcJMP {
  219.     long    jsrInst;
  220.     long    moveInst;
  221.     short    jmpInst;
  222.     long    jmpAddress;
  223. } cdefRsrcJMP;
  224. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  225. #ifdef powerc
  226. #pragma options align=reset
  227. #endif
  228.  
  229.  
  230.  
  231. /*****************************************************************************/
  232.  
  233.  
  234.  
  235. extern Boolean        gInBackground;
  236.  
  237. short    gTECtl    = rTECtl;
  238.  
  239. short    CTEGetLineNum(TEHandle te, short offset);
  240. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent);
  241.  
  242. static void                CTEInitialize(void);
  243. static pascal long        CTECtl(short varCode, ControlHandle ctl, short msg, long parm);
  244. static Boolean            GoFast(TEHandle teHndl, EventRecord *event);
  245. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  246.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon);
  247.  
  248. static pascal Boolean    PPCClikLoop(TEPtr pTE);
  249. static pascal void        PPCNoCaret(const Rect *r, TEPtr pTE);
  250.  
  251. static cdefRsrcJMPHndl    gCDEF;
  252. static Boolean            gCanGoSlow;
  253. static Boolean            gUseTSMTE;
  254. static WindowPtr        gTEWindow;
  255.  
  256.  
  257.  
  258. /*****************************************************************************/
  259.  
  260.  
  261.  
  262. TEClickLoopUPP    gDefaultClikLoopUPP;
  263.     /* The clikLoop TextEdit wants to use.  Our custom clikLoop must call
  264.     ** this as well.  The default TextEdit clikLoop is stored here. */
  265.  
  266. static ControlDefUPP    gCTECtlUPP;                /* Universal ProcPtr for CTECtl() */
  267. static TEClickLoopUPP    gClikLoopUPP;            /* Universal ProcPtr for our ClikLoop */
  268. static CaretHookUPP        gNoCaretHookUPP;        /* Universal ProcPtr for our CaretHook */
  269.  
  270.  
  271.  
  272. /*****************************************************************************/
  273.  
  274.  
  275.  
  276. static TEHandle            gActiveTEHndl;
  277.     /* Currently active TextEdit record.  (nil if none active.) */
  278.  
  279. static TEHandle            gFoundTEHndl;
  280.     /* Global value used to return info from the TextEdit control proc. */
  281.  
  282. static ControlHandle    gFoundViewCtl;
  283.     /* Global value used to return info from the TextEdit control proc. */
  284.  
  285. static pascal void        VActionProc(ControlHandle scrollCtl, short part);
  286. static pascal void        HActionProc(ControlHandle control, short part);
  287. static void                AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert);
  288.  
  289. #define kTELastForWind    1
  290. #define kCrChar            13
  291.  
  292.  
  293.  
  294. static void                dummyCTEActivate(Boolean active, TEHandle teHndl);
  295. static Boolean            dummyCTEClick(WindowPtr window, EventRecord *event, short *action);
  296. static ControlHandle    dummyCTECtlHit(void);
  297. static TEHandle            dummyCTEFindActive(WindowPtr window);
  298. static short            dummyCTEKey(WindowPtr window, EventRecord *event);
  299. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive);
  300. static void                dummyCTESetSelect(short start, short end, TEHandle teHndl);
  301. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl);
  302. static TEHandle            dummyCTEWindActivate(WindowPtr window, Boolean displayIt);
  303.  
  304. CTEActivateProcPtr           gcteActivate           = dummyCTEActivate;
  305. CTEClickProcPtr              gcteClick              = dummyCTEClick;
  306. CTECtlHitProcPtr             gcteCtlHit             = dummyCTECtlHit;
  307. CTEFindActiveProcPtr         gcteFindActive         = dummyCTEFindActive;
  308. CTEKeyProcPtr                gcteKey                = dummyCTEKey;
  309. CTENextProcPtr               gcteNext               = dummyCTENext;
  310. CTESetSelectProcPtr          gcteSetSelect          = dummyCTESetSelect;
  311. CTEViewFromTEProcPtr         gcteViewFromTE         = dummyCTEViewFromTE;
  312. CTEWindActivateProcPtr       gcteWindActivate       = dummyCTEWindActivate;
  313.  
  314.  
  315.  
  316. /*****************************************************************************/
  317. /*****************************************************************************/
  318.  
  319. #ifdef applec
  320. #pragma segment ATGTextEditControl
  321. #endif
  322.  
  323. /*****************************************************************************/
  324. /*****************************************************************************/
  325.  
  326.  
  327.  
  328. /* Instead of calling the functions directly, you can reference the global
  329. ** proc pointers that reference the functions.  This keeps everything from
  330. ** being linked in.  The default global proc pointers point to dummy functions
  331. ** that behave as if there aren't any TextEdit controls.  The calls can still be
  332. ** made, yet the runtime behavior is such that it will operate as if there
  333. ** no instances of the TextEdit control.  This allows intermediate code to access
  334. ** the functions or not without automatically linking in all sorts of stuff
  335. ** into the application that isn't desired.  To change the global proc pointers
  336. ** so that they point to the actual functions, just call CTEInitialize() once
  337. ** in the beginning of the application.  If CTEInitialize() is referenced, it will
  338. ** get linked in.  In turn, everything that it references directly or indirectly
  339. ** will get linked in. */
  340.  
  341. static void    CTEInitialize(void)
  342. {
  343.     if (gcteActivate != CTEActivate) {
  344.         gcteActivate           = CTEActivate;
  345.         gcteClick              = CTEClick;
  346.         gcteCtlHit             = CTECtlHit;
  347.         gcteFindActive         = CTEFindActive;
  348.         gcteKey                = CTEKey;
  349.         gcteNext               = CTENext;
  350.         gcteSetSelect          = CTESetSelect;
  351.         gcteViewFromTE         = CTEViewFromTE;
  352.         gcteWindActivate       = CTEWindActivate;
  353.  
  354.         CTEConvertClipboard(true, true);
  355.     }
  356. }
  357.  
  358.  
  359.  
  360. /*****************************************************************************/
  361.  
  362.  
  363.  
  364. /* Activate this TextEdit record.  If another is currently active, deactivate
  365. ** that one.  The view control for this TextEdit record is also flagged to
  366. ** indicate which was the last active one for this window.  If the previous
  367. ** active TextEdit record was in the same window, then flag the old one off
  368. ** for this window.  The whole point for this per-window flagging is so that
  369. ** activate events can reactivate the correct TextEdit control per window. */
  370.  
  371. void    CTEActivate(Boolean active, TEHandle teHndl)
  372. {
  373.     WindowPtr        tePort, oldPort;
  374.     ControlHandle    viewCtl;
  375.     TEHandle        te;
  376.     CTEDataHndl        teData;
  377.     short            oldDisplay, newDisplay;
  378.  
  379.     if (!teHndl) return;
  380.  
  381.     teData = nil;
  382.     viewCtl = CTEViewFromTE(teHndl);
  383.     if (viewCtl)
  384.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  385.  
  386.     if (!active) {
  387.         GetPort(&oldPort);
  388.         SetPort(tePort = (*teHndl)->inPort);
  389.         if(gUseTSMTE)
  390.             DeactivateTSMDocument((*teData)->docID);
  391.         TEDeactivate(teHndl);
  392.         if (teHndl == gActiveTEHndl)
  393.             gActiveTEHndl = nil;
  394.         if (viewCtl)
  395.             CTEUpdate(teHndl, viewCtl, true);
  396.         SetPort(oldPort);
  397.         return;
  398.     }
  399.  
  400.     if (!viewCtl)               return;
  401.     if (!(*viewCtl)->contrlVis) return;
  402.  
  403.     (*teData)->mode |= cteActive;
  404.     GetPort(&oldPort);
  405.     SetPort(tePort = (*teHndl)->inPort);
  406.  
  407.     if (!gInBackground) {
  408.         if(gUseTSMTE)
  409.             ActivateTSMDocument((*teData)->docID);
  410.         TEActivate(gActiveTEHndl = teHndl);
  411.     }
  412.  
  413.     CTEUpdate(teHndl, viewCtl, true);
  414.     SetPort(oldPort);
  415.         /* Let TextEdit know that it is supposed to be active. */
  416.  
  417.     for (viewCtl = nil;;) {
  418.         viewCtl = CTENext(tePort, &te, viewCtl, 1, false);
  419.         if (!viewCtl) break;
  420.         if (te != teHndl) {
  421.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  422.             oldDisplay = (*teData)->mode;
  423.             newDisplay = (oldDisplay & (0xFFFF - cteActive));
  424.             if (oldDisplay != newDisplay) {
  425.                 (*teData)->mode = newDisplay;
  426.                 CTEActivate(false, te);
  427.             }
  428.         }
  429.     }
  430. }
  431.  
  432.  
  433.  
  434. static void    dummyCTEActivate(Boolean active, TEHandle teHndl)
  435. {
  436. #ifndef __MWERKS__
  437. #pragma unused (active, teHndl)
  438. #endif
  439. }
  440.  
  441.  
  442.  
  443. /*****************************************************************************/
  444.  
  445.  
  446.  
  447. /* This is called when a mouseDown occurs in the content of a window.  It
  448. ** returns true if the mouseDown caused a TextEdit action to occur.  Events
  449. ** that are handled include if the user clicks on a scrollbar that is
  450. ** associated with a TextEdit control. */
  451.  
  452. Boolean    CTEClick(WindowPtr window, EventRecord *event, short *action)
  453. {
  454.     WindowPtr        oldPort;
  455.     Point            mouseLoc;
  456.     TEHandle        te, teActive;
  457.     ControlHandle    ctlHit, viewCtl;
  458.     CTEDataHndl        teData;
  459.     Boolean            vert;
  460.     short            extendSelect, part, value, newValue, lh, mode;
  461.  
  462.     static ControlActionUPP    hcupp, vcupp;
  463.  
  464.     if (action)
  465.         *action = 0;
  466.  
  467.     GetPort(&oldPort);
  468.     if (!((WindowPeek)window)->hilited) return(false);
  469.  
  470.     SetPort(window);
  471.     mouseLoc = event->where;
  472.     GlobalToLocal(&mouseLoc);
  473.  
  474.     if (!(viewCtl = CTEFindCtl(window, event, &te, &ctlHit))) return(false);
  475.  
  476.     if (viewCtl == ctlHit) {
  477.             /* See if the user clicked directly on the view control for a
  478.             ** TextEdit record.  If so, we definitely have some work to do. */
  479.         if ((*viewCtl)->contrlHilite != 255) {
  480.             if (te != gActiveTEHndl) {
  481.                 CTEActivate(true, te);
  482.                 if (action)
  483.                     *action = -1;
  484.                 SetPort(oldPort);
  485.                 return(true);
  486.                     /* If user clicked on TextEdit control other than the
  487.                     ** currently active control, then activate it.  This is our
  488.                     ** only action in this case. */
  489.             }
  490.             extendSelect = ((event->modifiers & shiftKey) != 0);
  491.                 /* Extend-select may be occuring. */
  492.  
  493.             gCanGoSlow = true;
  494.                 /* There is a slow-zone around the TextEdit area for slow extend-select.
  495.                 ** Allow this zone to slow down selection. */
  496.  
  497.                 if (gUseTSMTE) {
  498.                     if (!TSMEvent(event))
  499.                         TEClick(mouseLoc, extendSelect, te);
  500.                 }
  501.                 else TEClick(mouseLoc, extendSelect, te);
  502.                     /* Do the extend-select thing.  Most of the work is handled by
  503.                     ** TextEdit.  The only thing we have to do is to update the
  504.                     ** scrollbars while the user is extending the select.  This is
  505.                     ** taken care of by our custom clikLoop procedure. */
  506.  
  507.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  508.             (*teData)->newUndo = true;
  509.  
  510.             SetPort(oldPort);
  511.             return(true);
  512.         }
  513.     }
  514.  
  515. /* We didn't hit the view control for a TextEdit record, but don't give up yet.
  516. ** The user may be clicking on a related scrollbar.  Let's find out... */
  517.  
  518.     if (WhichControl(mouseLoc, event->when, window, &ctlHit)) {
  519.             /* The user did click on a control.  But is it a scrollbar
  520.             ** for a TextEdit control?  Stay tuned... */
  521.  
  522.         te = CTEFromScroll(ctlHit, &viewCtl);
  523.  
  524.         if (te) {        /* It was a related scrollbar. */
  525.  
  526.             if ((*viewCtl)->contrlHilite != 255) {
  527.                 if (te != gActiveTEHndl) {
  528.                     CTEActivate(true, te);
  529.                     if (action)
  530.                         *action = -1;
  531.                     SetPort(oldPort);
  532.                     return(true);
  533.                         /* If user clicked on TextEdit control other than the
  534.                         ** currently active control, then activate it.  This is our
  535.                         ** only action in this case. */
  536.                 }
  537.             }
  538.  
  539.             vert = ((*ctlHit)->contrlRect.top <= (*viewCtl)->contrlRect.top);
  540.                 /* Horizontal or vertical scroll.  Only the rect knows. */
  541.  
  542.             part = FindControl(mouseLoc, window, &ctlHit);
  543.  
  544.             switch (part) {
  545.                 case 0:        /* Inactive scrollbar. */
  546.                     break;
  547.                 case inThumb:
  548.                     value = GetControlValue(ctlHit);
  549.                     part  = TrackControl(ctlHit, mouseLoc, nil);
  550.                     if (part) {
  551.                         newValue = GetControlValue(ctlHit);
  552.                         if (value != newValue) {    /* If scrollbar value changed... */
  553.                             if (vert) {
  554.                                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  555.                                 mode   = (*teData)->mode;
  556.                                 if (mode & cteScrollFullLines) {
  557.                                     if (!(mode & cteStyledTE)) {
  558.                                         lh = CTEGetLineHeight(te, 1, nil);
  559.                                         if (lh) {
  560.                                             newValue += (lh >> 1);
  561.                                             newValue /= lh;
  562.                                             newValue *= lh;
  563.                                             SetControlValue(ctlHit, newValue);
  564.                                         }
  565.                                     }
  566.                                 }
  567.                                 TEScroll(0, value - newValue, te);
  568.                             }
  569.                             else
  570.                                 TEScroll(value - newValue, 0, te);
  571.                         }
  572.                     }
  573.                     break;
  574.  
  575.                 default:
  576.                     teActive = gActiveTEHndl;
  577.                     gActiveTEHndl = te;
  578.                         /* This is a hack way to pass the action procedure
  579.                         ** which TextEdit record we are dealing with. */
  580.  
  581.                     if (vert) {
  582.                         if (!vcupp) vcupp = NewControlActionProc(VActionProc);
  583.                         TrackControl(ctlHit, mouseLoc, vcupp);
  584.                     }
  585.                     else {
  586.                         if (!hcupp) hcupp = NewControlActionProc(HActionProc);
  587.                         TrackControl(ctlHit, mouseLoc, hcupp);
  588.                     }
  589.  
  590.                     gActiveTEHndl = teActive;
  591.                         /* Unhack our previous hack. */
  592.                     break;
  593.             }
  594.  
  595.             SetPort(oldPort);
  596.             return(true);
  597.         }
  598.     }
  599.  
  600.     SetPort(oldPort);
  601.     return(false);
  602. }
  603.  
  604.  
  605.  
  606. static Boolean    dummyCTEClick(WindowPtr window, EventRecord *event, short *action)
  607. {
  608. #ifndef __MWERKS__
  609. #pragma unused (window, event)
  610. #endif
  611.  
  612.     if (action)
  613.         *action = 0;
  614.     return(false);
  615. }
  616.  
  617.  
  618.  
  619. /*****************************************************************************/
  620.  
  621.  
  622.  
  623. /* This is the custom clikLoop, which is called from the assembly glue code.
  624. ** This handles updating the scrollbars as the user is drag-selecting in
  625. ** the TextEdit control. */
  626.  
  627. void    CTEClikLoop(void)
  628. {
  629.     WindowPtr        oldPort, window;
  630.     TEHandle        te;
  631.     Point            mouseLoc;
  632.     Rect            viewRct;
  633.     RgnHandle        rgn;
  634.     short            dl, dr, dt, db;
  635.     long            tick;
  636.  
  637.     GetPort(&oldPort);
  638.     SetPort(window = (WindowPtr)(*gActiveTEHndl)->inPort);
  639.  
  640.     te = gActiveTEHndl;
  641.         /* This better be what the user is dragging, or we did something
  642.         ** wrong elsewhere.
  643.         */
  644.  
  645.     GetMouse(&mouseLoc);
  646.     viewRct = (*te)->viewRect;
  647.  
  648.     if (!PtInRect(mouseLoc, &viewRct)) {
  649.         /* User is outside the TextEdit area, so scrolling is happening. */
  650.  
  651.         tick = gCanGoSlow;
  652.         if (tick)
  653.             tick = TickCount();
  654.                 /* As an extra feature, there is a zone around the TextEdit
  655.                 ** viewRct that the scroll will be slowed down.  If the user
  656.                 ** drags outside the viewRct outside this zone, then scrolling
  657.                 ** occurs as fast as possible. */
  658.  
  659.         rgn = NewRgn();
  660.         GetClip(rgn);
  661.         ClipRect(&(window->portRect));
  662.             /* The clipRgn is set to protect everything outside viewRct.
  663.             ** This doesn't work very well when we want to change
  664.             ** the scrollbars.  Save the old and open it up.
  665.             */
  666.  
  667.         dl = viewRct.left - mouseLoc.h;
  668.         dr = mouseLoc.h   - viewRct.right;
  669.         dt = viewRct.top  - mouseLoc.v;
  670.         db = mouseLoc.v   - viewRct.bottom;
  671.             /* Check the delta value for each side of viewRct.  This will
  672.             ** be used to determine if we should scroll fast or slow.
  673.             */
  674.  
  675.         CTEAdjustScrollValues(te);
  676.             /* Scroll them puppies. */
  677.  
  678.         SetClip(rgn);                                /* restore clip */
  679.         DisposeRgn(rgn);
  680.             /* Make Mr. clipRgn happy again. */
  681.  
  682.         if ((dl < 16) && (dr < 16) && (dt < 16) && (db < 16))
  683.             while (tick + 10 > TickCount()) {};
  684.                 /* Do it really slow.  (This is important on very fast machines.) */
  685.     }
  686.  
  687.     SetPort(oldPort);
  688. }
  689.  
  690.  
  691.  
  692. /*****************************************************************************/
  693.  
  694.  
  695.  
  696. /* Do the cut/copy/paste/clear operations for the currently active
  697. ** TextEdit control.  Caller assumes appropriateness of the call.  Typically,
  698. ** this routine won't be called at an inappropriate time, since the menu
  699. ** item should be enabled or disabled correctly.
  700. ** Use CTEEditMenu to set the menu items undo/cut/copy/paste/clear correctly
  701. ** for the active TextEdit control.  Since undo isn't currently supported,
  702. ** all that CTEEditMenu does for the undo case is to deactivate it right now. */
  703.  
  704. ControlHandle    CTEClipboard(short menuID)
  705. {
  706.     WindowPtr        oldPort;
  707.     TEHandle        te;
  708.     ControlHandle    viewCtl;
  709.     CTEDataHndl        teData;
  710.     long            maxTextLen, charsToAdd;
  711.  
  712.     if (!(te = gActiveTEHndl))          return(nil);
  713.     if (!(viewCtl = CTEViewFromTE(te))) return(nil);
  714.  
  715.     GetPort(&oldPort);
  716.     SetPort((*te)->inPort);
  717.     switch (menuID) {
  718.         case 2:
  719.             CTENewUndo(viewCtl, true);
  720.             TECut(te);
  721.             break;
  722.         case 3:
  723.             TECopy(te);
  724.             viewCtl = nil;
  725.             break;
  726.         case 4:
  727.             if (viewCtl) {
  728.                 teData = (CTEDataHndl)(*viewCtl)->contrlData;
  729.                 maxTextLen  = (*teData)->maxTextLen;
  730.                 charsToAdd  = TEGetScrapLength();
  731.                 charsToAdd -= ((*te)->selEnd - (*te)->selStart);
  732.                 if ((*te)->teLength + charsToAdd <= maxTextLen) {
  733.                     CTENewUndo(viewCtl, true);
  734.                     if ((*teData)->mode & cteStyledTE)
  735.                         TEStylePaste(te);
  736.                     else
  737.                         TEPaste(te);
  738.                 }
  739.                 else viewCtl = nil;
  740.             }
  741.             break;
  742.         case 5:
  743.             CTENewUndo(viewCtl, true);
  744.             TEDelete(te);
  745.             break;
  746.     }
  747.  
  748.     CTEAdjustTEBottom(te);
  749.     CTEAdjustScrollValues(te);
  750.     SetPort(oldPort);
  751.  
  752.     return(viewCtl);
  753. }
  754.  
  755.  
  756.  
  757. /*****************************************************************************/
  758.  
  759.  
  760.  
  761. void    CTEConvertClipboard(Boolean convertClipboard, Boolean becomingActive)
  762. {
  763. #ifndef __MWERKS__
  764. #pragma unused (convertClipboard, becomingActive)
  765. #endif
  766. }
  767.  
  768.  
  769.  
  770. /*****************************************************************************/
  771.  
  772.  
  773.  
  774. static pascal long    CTECtl(short varCode, ControlHandle ctl, short msg, long parm)
  775. {
  776. #ifndef __MWERKS__
  777. #pragma unused (varCode)
  778. #endif
  779.  
  780.     Rect            viewRct;
  781.     TEHandle        te;
  782.     CTEDataHndl        teData;
  783.     ControlHandle    scrollCtl;
  784.     short            i;
  785.  
  786.     te = (TEHandle)GetControlReference(ctl);
  787.     if (te)
  788.         viewRct = (*ctl)->contrlRect;
  789.     else
  790.         SetRect(&viewRct, 0, 0, 0, 0);
  791.  
  792.     switch (msg) {
  793.         case drawCntl:
  794.             CTEUpdate(te, ctl, false);
  795.             break;
  796.  
  797.         case testCntl:
  798.             if (PtInRect(*(Point *)&parm, &viewRct)) {
  799.                 gFoundViewCtl = ctl;
  800.                 gFoundTEHndl  = te;
  801.                 return(1);
  802.             }
  803.             return(0);
  804.             break;
  805.  
  806.         case calcCRgns:
  807.         case calcCntlRgn:
  808.             if (msg == calcCRgns)
  809.                 parm &= 0x00FFFFFF;
  810.             RectRgn((RgnHandle)parm, &viewRct);
  811.             break;
  812.  
  813.         case initCntl:
  814.             break;
  815.  
  816.         case dispCntl:
  817.             if (te) {
  818.                 if (te == gActiveTEHndl)
  819.                     gActiveTEHndl = nil;
  820.                 TEDispose(te);
  821.                 teData = (CTEDataHndl)(*ctl)->contrlData;
  822.                 if (teData) {
  823.                     if ((*teData)->undoText)
  824.                         DisposeHandle((Handle)(*teData)->undoText);
  825.                     if ((*teData)->undoStyl)
  826.                         DisposeHandle((Handle)(*teData)->undoStyl);
  827.                     if ((*teData)->docID)
  828.                         DeleteTSMDocument((*teData)->docID);
  829.                     DisposeHandle((Handle)teData);
  830.                 }
  831.                 for (i = 0; i < 2; ++i) {
  832.                     scrollCtl = CTEScrollFromView(ctl, i);
  833.                     if (scrollCtl)
  834.                         DisposeControl(scrollCtl);
  835.                 }
  836.             }
  837.             break;
  838.  
  839.         case posCntl:
  840.             break;
  841.  
  842.         case thumbCntl:
  843.             break;
  844.  
  845.         case dragCntl:
  846.             break;
  847.  
  848.         case autoTrack:
  849.             break;
  850.     }
  851.  
  852.     return(0);
  853. }
  854.  
  855.  
  856.  
  857. /*****************************************************************************/
  858.  
  859.  
  860.  
  861. /* The TextEdit control that was hit by calling FindControl is saved in a
  862. ** global variable, since the CDEF has no way of returning what kind it was.
  863. ** To determine that it was a TextEdit control that was hit, first call this
  864. ** function.  The first call returns the old value in the global variable,
  865. ** plus it resets the global to nil.  Then call FindControl(), and then
  866. ** call this function again.  If it returns nil, then a TextEdit control
  867. ** wasn't hit.  If it returns non-nil, then it was a TextEdit control that
  868. ** was hit, and specifically the one returned. */
  869.  
  870. ControlHandle    CTECtlHit(void)
  871. {
  872.     ControlHandle    ctl;
  873.  
  874.     ctl = gFoundViewCtl;
  875.     gFoundViewCtl = nil;
  876.     return(ctl);
  877. }
  878.  
  879.  
  880.  
  881. static ControlHandle    dummyCTECtlHit(void)
  882. {
  883.     return(nil);
  884. }
  885.  
  886.  
  887.  
  888. /*****************************************************************************/
  889.  
  890.  
  891.  
  892. /* Disposes of the TERecord, TextEdit control, and any related scrollbars. */
  893.  
  894. void    CTEDispose(TEHandle teHndl)
  895. {
  896.     WindowPtr    oldPort;
  897.  
  898.     if (teHndl) {
  899.         GetPort(&oldPort);
  900.         SetPort((*teHndl)->inPort);
  901.         TEDispose(CTEDisposeView(CTEViewFromTE(teHndl)));
  902.             /* Dispose of the TextEdit control completely.  This includes
  903.             ** scrollbars, as well as the TextEdit view control.
  904.             */
  905.         SetPort(oldPort);
  906.     }
  907. }
  908.  
  909.  
  910.  
  911. /*****************************************************************************/
  912.  
  913.  
  914.  
  915. /* Dispose of the view control and related scrollbars.  This function also
  916. ** returns the handle to the TextEdit record, since it was just orphaned.
  917. ** Use this function if you want to get rid of a TextEdit control, but you
  918. ** want to keep the TextEdit record. */
  919.  
  920. TEHandle    CTEDisposeView(ControlHandle viewCtl)
  921. {
  922.     TEHandle        te;
  923.     short            vert;
  924.     ControlHandle    ctl;
  925.  
  926.     if (!viewCtl) return(nil);
  927.  
  928.     te = (TEHandle)GetControlReference(viewCtl);
  929.     SetControlReference(viewCtl, (long)nil);
  930.  
  931.     for (vert = 0; vert < 2; ++vert) {
  932.         ctl = CTEScrollFromView(viewCtl, vert);
  933.         if (ctl)
  934.             DisposeControl(ctl);
  935.     }
  936.  
  937.     DisposeControl(viewCtl);
  938.     return(te);
  939. }
  940.  
  941.  
  942.  
  943. /*****************************************************************************/
  944.  
  945.  
  946.  
  947. /* Returns the full document height. */
  948.  
  949. short    CTEDocHeight(TEHandle teHndl)
  950. {
  951.     short        h, lh, a;
  952.     TextStyle    st;
  953.  
  954.     if (!teHndl) return(0);
  955.  
  956.     h = TEGetHeight((*teHndl)->nLines, 1, teHndl);
  957.         /* Get the whole doc height. */
  958.  
  959.     if ((*teHndl)->nLines != CTENumTextLines(teHndl)) {        /* If # of lines is wrong by one... */
  960.         TEGetStyle((*teHndl)->teLength, &st, &lh, &a, teHndl);
  961.         h += lh;                                            /* Add in height of last line. */
  962.     }
  963.  
  964.     return(h);
  965. }
  966.  
  967.  
  968.  
  969. /*****************************************************************************/
  970.  
  971.  
  972.  
  973. /* Enable or disable edit menu items based on the active TextEdit control.
  974. ** You pass the menu ID of the undo item in undoID, and the menu ID of the
  975. ** cut item in cutID.  If undoID or cutID is non-zero, then some action is
  976. ** performed.  If you pass a non-zero value for cutID, then the other menu
  977. ** items cut/copy/paste/clear are updated to reflect the status of the
  978. ** active TextEdit control. */
  979.  
  980. Boolean    CTEEditMenu(Boolean *activeItem, short editMenu, short undoID, short cutID)
  981. {
  982.     TEHandle        te;
  983.     MenuHandle        menu;
  984.     Boolean            active;
  985.     ControlHandle    viewCtl;
  986.     CTEDataHndl        teData;
  987.     long            dataLen, scrapOffset;
  988.  
  989.     active = false;
  990.     if (activeItem) *activeItem = false;
  991.     menu = GetMenuHandle(editMenu);
  992.  
  993.     if (undoID)
  994.         DisableItem(menu, undoID);
  995.  
  996.     if (cutID) {
  997.         DisableItem(menu, cutID);            /* Disable cut. */
  998.         DisableItem(menu, cutID + 1);        /* Disable copy. */
  999.         DisableItem(menu, cutID + 2);        /* Disable paste. */
  1000.         DisableItem(menu, cutID + 3);        /* Disable clear. */
  1001.     }
  1002.  
  1003.     if (!(te = gActiveTEHndl)) return(false);
  1004.  
  1005.     if (undoID) {
  1006.         viewCtl = CTEViewFromTE(te);
  1007.         if (viewCtl) {
  1008.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1009.             if ((*teData)->undoText) {
  1010.                 EnableItem(menu, undoID);
  1011.                 active = true;
  1012.             }
  1013.         }
  1014.     }
  1015.  
  1016.     if (cutID) {
  1017.         if ((*te)->selStart != (*te)->selEnd) {
  1018.             if (!CTEReadOnly(te)) {
  1019.                 EnableItem(menu, cutID);        /* Enable cut. */
  1020.                 EnableItem(menu, cutID + 3);    /* Enable clear. */
  1021.             }
  1022.             active = true;
  1023.             EnableItem(menu, cutID + 1);        /* Enable copy. */
  1024.         }
  1025.         if (!CTEReadOnly(te)) {
  1026.             dataLen = GetScrap(nil, 'TEXT', &scrapOffset);
  1027.             if (dataLen > 0) {
  1028.                 active = true;
  1029.                 EnableItem(menu, cutID + 2);        /* Enable paste. */
  1030.             }
  1031.         }
  1032.     }
  1033.  
  1034.     if (activeItem)
  1035.         *activeItem = active;
  1036.  
  1037.     return(true);
  1038. }
  1039.  
  1040.  
  1041.  
  1042. /*****************************************************************************/
  1043.  
  1044.  
  1045.  
  1046. /* Handle the event if it applies to the active TextEdit control.  If some
  1047. ** action occured due to the event, return true. */
  1048.  
  1049. Boolean    CTEEvent(WindowPtr window, EventRecord *event, short *action)
  1050. {
  1051.     WindowPtr    clickWindow;
  1052.     short        actn;
  1053.  
  1054.     if (action)
  1055.         *action = 0;
  1056.  
  1057.     switch(event->what) {
  1058.  
  1059.         case mouseDown:
  1060.             if (FindWindow(event->where, &clickWindow) == inContent)
  1061.                 if (window == clickWindow)
  1062.                     if (((WindowPeek)window)->hilited) return(CTEClick(window, event, action));
  1063.             break;
  1064.  
  1065.         case autoKey:
  1066.         case keyDown:
  1067.             if (!(event->modifiers & cmdKey)) {
  1068.                 actn = CTEKey(window, event);
  1069.                 if (action)
  1070.                     *action = actn;
  1071.                 if (actn) return(true);
  1072.             }
  1073.             break;
  1074.     }
  1075.  
  1076.     return(false);
  1077. }
  1078.  
  1079.  
  1080.  
  1081. /*****************************************************************************/
  1082.  
  1083.  
  1084.  
  1085. /* Returns the active TextEdit control, if any.  If nil is passed in, then
  1086. ** the return value represents whatever TextEdit control is active, independent
  1087. ** of what window it is in.  If a window is passed in, then it returns a
  1088. ** TextEdit control only if the active control is in the specified window.
  1089. ** If the active TextEdit control is in some other window, then nil is returned. */
  1090.  
  1091. TEHandle    CTEFindActive(WindowPtr window)
  1092. {
  1093.     if (!window) return(gActiveTEHndl);
  1094.         /* User wants whatever is active one, for whatever window. */
  1095.  
  1096.     if (!gActiveTEHndl) return(nil);
  1097.     if (window != (*gActiveTEHndl)->inPort) return(nil);
  1098.     return(gActiveTEHndl);
  1099. }
  1100.  
  1101.  
  1102.  
  1103. static TEHandle    dummyCTEFindActive(WindowPtr window)
  1104. {
  1105. #ifndef __MWERKS__
  1106. #pragma unused (window)
  1107. #endif
  1108.     return(nil);
  1109. }
  1110.  
  1111.  
  1112.  
  1113. /*****************************************************************************/
  1114.  
  1115.  
  1116.  
  1117. /* This determines if a TextEdit control was clicked on directly.  This does
  1118. ** not determine if a related scrollbar was clicked on.  If a TextEdit
  1119. ** control was clicked on, then true is returned, as well as the TextEdit
  1120. ** handle and the handle to the view control. */
  1121.  
  1122. ControlHandle    CTEFindCtl(WindowPtr window, EventRecord *event, TEHandle *teHndl, ControlHandle *ctlHit)
  1123. {
  1124.     WindowPtr        oldPort;
  1125.     Point            mouseLoc;
  1126.     ControlHandle    ctl, tectl;
  1127.     TEHandle        te;
  1128.  
  1129.     if (ctlHit) *ctlHit = nil;
  1130.     if (teHndl) *teHndl = nil;
  1131.  
  1132.     gFoundTEHndl = nil;
  1133.  
  1134.     if (window) {
  1135.         GetPort(&oldPort);
  1136.         SetPort(window);
  1137.         mouseLoc = event->where;
  1138.         GlobalToLocal(&mouseLoc);
  1139.         SetPort(oldPort);
  1140.  
  1141.         if (!WhichControl(mouseLoc, 0, window, &ctl)) return(nil);
  1142.             /* Didn't hit a thing, so forget it. */
  1143.  
  1144.         te = CTEFromScroll(ctl, &tectl);
  1145.         if (te) {
  1146.             if (ctlHit)
  1147.                 *ctlHit = ctl;
  1148.             if (teHndl)
  1149.                 *teHndl = te;
  1150.             return(tectl);
  1151.         }
  1152.  
  1153.         FindControl(mouseLoc, window, &ctl);
  1154.         if (!ctl)                                                        return(nil);
  1155.         if (StripAddress((*ctl)->contrlDefProc) != StripAddress(gCDEF)) return(nil);
  1156.             /* Control hit was above TE control, so we didn't hit a TE control. */
  1157.         if (ctlHit)
  1158.             *ctlHit = ctl;
  1159.         if (teHndl)
  1160.             *teHndl = gFoundTEHndl;
  1161.         if (gFoundTEHndl) return(ctl);
  1162.     }
  1163.  
  1164.     return(nil);
  1165. }
  1166.  
  1167.  
  1168.  
  1169. /*****************************************************************************/
  1170.  
  1171.  
  1172.  
  1173. /* Find the TextEdit record that is related to the indicated scrollbar. */
  1174.  
  1175. TEHandle    CTEFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
  1176. {
  1177.     WindowPtr        window;
  1178.     ControlHandle    viewCtl;
  1179.     TEHandle        te;
  1180.  
  1181.     if (!IsScrollBar(scrollCtl)) {
  1182.         if (retCtl) *retCtl = nil;
  1183.         return(nil);
  1184.     }
  1185.  
  1186.     window = (*scrollCtl)->contrlOwner;
  1187.  
  1188.     for (viewCtl = nil;;) {
  1189.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  1190.         if (!viewCtl) return(nil);
  1191.         if (viewCtl == (ControlHandle)GetControlReference(scrollCtl)) {
  1192.             if (retCtl) *retCtl = viewCtl;
  1193.             return(te);
  1194.         }
  1195.     }
  1196. }
  1197.  
  1198.  
  1199.  
  1200. /*****************************************************************************/
  1201.  
  1202.  
  1203.  
  1204. /* Hide the designated TextEdit control and related scrollbars. */
  1205.  
  1206. Rect    CTEHide(TEHandle teHndl)
  1207. {
  1208.     ControlHandle    viewCtl, scrollCtl;
  1209.     short            i, mode;
  1210.     CTEDataHndl        teData;
  1211.     Rect            viewRct, brdrRct;
  1212.  
  1213.     SetRect(&brdrRct, 0, 0, 0, 0);
  1214.  
  1215.     if (teHndl) {
  1216.         CTEActivate(false, teHndl);
  1217.         viewCtl = CTEViewFromTE(teHndl);
  1218.         if (viewCtl) {
  1219.             HideControl(viewCtl);
  1220.             for (i = 0; i < 2; i++) {
  1221.                 scrollCtl = CTEScrollFromView(viewCtl, i);
  1222.                 if (scrollCtl)
  1223.                     HideControl(scrollCtl);
  1224.             }
  1225.  
  1226.             teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1227.             mode    = (*teData)->mode;
  1228.             viewRct = (*teHndl)->viewRect;
  1229.             brdrRct = (*teData)->brdrRect;
  1230.         
  1231.             if (EmptyRect(&brdrRct)) brdrRct = viewRct;
  1232.  
  1233.             if (mode & cteVScroll) brdrRct.right  += 15;
  1234.             if (mode & cteHScroll) brdrRct.bottom += 15;
  1235.  
  1236.             if (mode & cteShowActive) InsetRect(&brdrRct, -3, -3);
  1237.         }
  1238.     }
  1239.  
  1240.     return(brdrRct);
  1241. }
  1242.  
  1243.  
  1244.  
  1245. /*****************************************************************************/
  1246.  
  1247.  
  1248.  
  1249. /* Blink the caret in the active TextEdit control.  The active TextEdit
  1250. ** control may be read-only, in which case the caret does not blink. */
  1251.  
  1252. void    CTEIdle(void)
  1253. {
  1254.     WindowPtr        window;
  1255.     ControlHandle    viewCtl;
  1256.     Rect            rct;
  1257.  
  1258.     if (gActiveTEHndl) {
  1259.         if (!(viewCtl = CTEViewFromTE(gActiveTEHndl))) return;
  1260.         if (!((*viewCtl)->contrlVis))                  return;
  1261.         if ((*viewCtl)->contrlHilite == 255)           return;
  1262.         window = (*gActiveTEHndl)->inPort;
  1263.         if (((WindowPeek)window)->hilited) {
  1264.             if (GetWRefCon(window)) {
  1265.                 rct = (*(((WindowPeek)window)->updateRgn))->rgnBBox;
  1266.                 if (EmptyRect(&rct))
  1267.                     TEIdle(gActiveTEHndl);
  1268.             }
  1269.         }
  1270.     }
  1271. }
  1272.  
  1273.  
  1274.  
  1275. /*****************************************************************************/
  1276.  
  1277.  
  1278.  
  1279. /* See if the keypress event applies to the TextEdit control, and if it does,
  1280. ** handle it and return non-zero.  If the key caused a change in the TERecord,
  1281. ** return 2.  If the key was handled with no change to the TERecord, return 1. */
  1282.  
  1283. short    CTEKey(WindowPtr window, EventRecord *event)
  1284. {
  1285.     TEHandle            te;
  1286.     ControlHandle        viewCtl;
  1287.     short                maxTextLen, selStart, selEnd;
  1288.     short                textSelected, arrowKey, retval;
  1289.     char                key;
  1290.     CTEDataHndl            teData;
  1291.     CTEKeyFilterProcPtr    kproc;
  1292.     CTEFastKeysProcPtr    fproc;
  1293.     short                handled;
  1294.     Boolean                looping, refig, tsmHandled;
  1295.     EventRecord            lclEvent;
  1296.  
  1297.     if (!(te = gActiveTEHndl))                return(0);
  1298.     if ((*gActiveTEHndl)->inPort != window) return(0);
  1299.     if (CTEReadOnly(te))                    return(0);
  1300.     if (!(viewCtl = CTEViewFromTE(te)))        return(0);
  1301.     if ((*viewCtl)->contrlHilite == 255)    return(0);
  1302.  
  1303.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1304.     handled = 0;
  1305.     kproc = (*teData)->keyFilter;
  1306.     if (kproc)
  1307.         if ((*kproc)(te, event, &handled))
  1308.             return(handled);
  1309.  
  1310.     retval = 1;
  1311.  
  1312.     for (refig = looping = false;; looping = true) {
  1313.  
  1314.         if (looping) {
  1315.  
  1316.             if (!(fproc = (*teData)->fastKeys)) {
  1317.                 if (refig) {
  1318.                     CTEAdjustTEBottom(te);
  1319.                     CTEAdjustScrollValues(te);
  1320.                 }
  1321.                 return(retval);
  1322.             }                        /* No fast keys looping proc defined, so leave. */
  1323.  
  1324.             if ((gSystemVersion >= 0x0700) && (HMGetBalloons())) {
  1325.                 if (refig) {
  1326.                     CTEAdjustTEBottom(te);
  1327.                     CTEAdjustScrollValues(te);
  1328.                 }
  1329.                 return(retval);
  1330.             }                        /* Don't call OSEventAvail if balloons are active, since
  1331.                                     ** the help manager may move a balloon when it is called.
  1332.                                     ** If we moved balloons now, that might be bad, since it
  1333.                                     ** is likely that BeginContent was called prior to getting
  1334.                                     ** here.  BeginContent calls BeginUpdate, which munges the
  1335.                                     ** visRgn.  If balloons were managed, then visRgns would get
  1336.                                     ** recalculated, and this would mess up our munged balloon. */
  1337.  
  1338.             event = &lclEvent;
  1339.             if (!OSEventAvail((mDownMask | keyDownMask | autoKeyMask), event)) {
  1340.                 if (refig) {
  1341.                     CTEAdjustTEBottom(te);
  1342.                     CTEAdjustScrollValues(te);
  1343.                 }
  1344.                 return(retval);
  1345.             }
  1346.  
  1347.             if (kproc) {
  1348.                 handled = 0;
  1349.                 if ((*kproc)(te, event, &handled)) {
  1350.                     if (refig) {
  1351.                         CTEAdjustTEBottom(te);
  1352.                         CTEAdjustScrollValues(te);
  1353.                     }
  1354.                     return(retval);
  1355.                 }
  1356.             }
  1357.  
  1358.             if (!(*fproc)(te, event)) {
  1359.                 if (refig) {
  1360.                     CTEAdjustTEBottom(te);
  1361.                     CTEAdjustScrollValues(te);
  1362.                 }
  1363.                 return(retval);
  1364.             }
  1365.  
  1366.             GetOSEvent((mDownMask | keyDownMask | autoKeyMask), event);
  1367.         }
  1368.  
  1369.         maxTextLen = (*teData)->maxTextLen;
  1370.         key        = event->message & charCodeMask;
  1371.         selStart   = (*te)->selStart;
  1372.         selEnd     = (*te)->selEnd;
  1373.         if (selStart > selEnd) {
  1374.             selStart = selEnd;
  1375.             selEnd = (*te)->selStart;
  1376.         }
  1377.         textSelected = (selStart != selEnd);
  1378.         arrowKey     = ((key >= chLeft) && (key <= chDown));
  1379.  
  1380.         if (
  1381.             (textSelected) ||                /* If selection range to be replaced or */
  1382.             (arrowKey) ||                    /* key is an arrow or                    */
  1383.             (key == 8) ||                    /* key is a delete or                   */
  1384.             ((*te)->teLength < maxTextLen)    /* we have space for the key...         */
  1385.         ) {
  1386.             tsmHandled = false;
  1387.             if (gUseTSMTE) {
  1388.                 tsmHandled = TSMEvent(event);
  1389.                 if (tsmHandled)
  1390.                     if (!arrowKey)
  1391.                         retval = 2;
  1392.             }
  1393.             if (!tsmHandled) {
  1394.                 if (arrowKey) {
  1395.                     (*teData)->newUndo = true;
  1396.                     TEKey(key, te);
  1397.                 }
  1398.                 else {
  1399.                     CTENewUndo(viewCtl, false);        /* Process the character... */
  1400.                     TEKey(key, te);
  1401.                     retval = 2;
  1402.                 }
  1403.             }
  1404.             refig = true;
  1405.         }
  1406.     }
  1407. }
  1408.  
  1409.  
  1410.  
  1411. static short    dummyCTEKey(WindowPtr window, EventRecord *event)
  1412. {
  1413. #ifndef __MWERKS__
  1414. #pragma unused (window, event)
  1415. #endif
  1416.     return(0);
  1417. }
  1418.  
  1419.  
  1420.  
  1421. /*****************************************************************************/
  1422.  
  1423.  
  1424.  
  1425. /* This function is used to move a TextEdit control.  Pass it the TextEdit
  1426. ** record to move, plus the new position.  It will move the TextEdit control,
  1427. ** along with any scrollbars the control may have.  All areas that need
  1428. ** updating are cleared and invalidated. */
  1429.  
  1430. void    CTEMove(TEHandle teHndl, short newH, short newV)
  1431. {
  1432.     WindowPtr        oldPort;
  1433.     Rect            viewRct, brdrRct, rct;
  1434.     short            i, dx, dy, mode;
  1435.     Boolean            hScroll, vScroll;
  1436.     ControlHandle    viewCtl, ctl;
  1437.     CTEDataHndl        teData;
  1438.     char            vis;
  1439.  
  1440.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  1441.  
  1442.     GetPort(&oldPort);
  1443.     SetPort((*teHndl)->inPort);
  1444.  
  1445.     viewRct = (*viewCtl)->contrlRect;
  1446.     vis     = (*viewCtl)->contrlVis;
  1447.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  1448.     brdrRct = (*teData)->brdrRect;
  1449.     mode    = (*teData)->mode;
  1450.  
  1451.     dx = newH - viewRct.left;
  1452.     dy = newV - viewRct.top;
  1453.     if ((!dx) && (!dy)) return;
  1454.  
  1455.     hScroll = (mode & cteHScroll) ? 1 : 0;
  1456.     vScroll = (mode & cteVScroll) ? 1 : 0;
  1457.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  1458.  
  1459.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  1460.     if (!EmptyRect(&brdrRct))
  1461.         UnionRect(&rct, &brdrRct, &rct);
  1462.     if (vScroll)
  1463.         rct.right += 15;
  1464.     if (hScroll)
  1465.         rct.bottom += 15;
  1466.     if (mode & cteShowActive)
  1467.         InsetRect(&rct, -4, -4);
  1468.     if (vis) {
  1469.         EraseRect(&rct);
  1470.         InvalRect(&rct);
  1471.     }
  1472.  
  1473.     for (i = 0; i < 2; ++i) {
  1474.         ctl = CTEScrollFromView(viewCtl, i);
  1475.         if (ctl) {
  1476.             rct = (*ctl)->contrlRect;
  1477.             MoveControl(ctl, rct.left + dx, rct.top + dy);
  1478.         }
  1479.     }
  1480.  
  1481.     OffsetRect(&viewRct, dx, dy);
  1482.     if (vis) InvalRect(&viewRct);
  1483.     OffsetRect(&brdrRct, dx, dy);
  1484.     if (vis) InvalRect(&brdrRct);
  1485.  
  1486.     (*viewCtl)->contrlRect = viewRct;
  1487.     (*teData)->brdrRect    = brdrRct;
  1488.  
  1489.     OffsetRect(&(*teHndl)->destRect, dx, dy);
  1490.     OffsetRect(&(*teHndl)->viewRect, dx, dy);
  1491.  
  1492.     viewRct.top  = viewRct.bottom - 16;
  1493.     viewRct.left = viewRct.right  - 16;
  1494.  
  1495.     if (vis)
  1496.         if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll))
  1497.             EraseRect(&viewRct);
  1498.  
  1499.     if (mode & (cteVScrollLessGrow - cteVScroll))
  1500.         OffsetRect(&viewRct, 16, 0);
  1501.     if (mode & (cteHScrollLessGrow - cteHScroll))
  1502.         OffsetRect(&viewRct, 0, 16);
  1503.     if (vis) InvalRect(&viewRct);
  1504.  
  1505.     SetPort(oldPort);
  1506. }
  1507.  
  1508.  
  1509.  
  1510. /*****************************************************************************/
  1511.  
  1512.  
  1513.  
  1514. /* Create a new TextEdit control.  See the comments at the beginning of this
  1515. ** file for more information.  Note that this function doesn't get a dummy,
  1516. ** as you really mean to have this code if you call it.  It calls CTEInitialize(),
  1517. ** just to make sure that the proc pointers are set to point to the real function,
  1518. ** instead of the dummy functions.  By having CLTENew() call CTEInitialize(), the
  1519. ** application won't have to worry about calling CTEInitialize().  By the time that
  1520. ** the application is using a TextEdit control, the proc pointers will be initialized. */
  1521.  
  1522. OSErr    CTENew(short viewID, Boolean vis, WindowPtr window, TEHandle *teHndl, Rect *cRect, Rect *dRect,
  1523.                Rect *vRect, Rect *bRect, short maxTextLen, short mode)
  1524. {
  1525.     Rect                        ctlRct, destRct, viewRct, brdrRct, scrollRct;
  1526.     WindowPtr                    oldPort;
  1527.     TEHandle                    te;
  1528.     short                        width, height, lh, a;
  1529.     ControlHandle                viewCtl, hScrollCtl, vScrollCtl;
  1530.     CTEDataHndl                    teData;
  1531.     TextStyle                    styl;
  1532.     OSErr                        err;
  1533.     TSMDocumentID                docID;
  1534.     TSMTERecHandle                tsmRec;
  1535.     static TSMTEPostUpdateUPP    tsmteupp;
  1536.     static OSType                supportedInterfaceTypes[] = {kTSMTEInterfaceType};
  1537.  
  1538.     CTEInitialize();
  1539.  
  1540.     if (teHndl)
  1541.         *teHndl = nil;            /* Assume that we will fail. */
  1542.  
  1543.     GetPort(&oldPort);
  1544.     SetPort(window);
  1545.  
  1546.     ctlRct  = *cRect;
  1547.     destRct = *dRect;
  1548.     viewRct = *vRect;
  1549.     brdrRct = *bRect;
  1550.         /* Make sure that the rects are not in memory that may move. */
  1551.  
  1552.     te = TEStyleNew(&destRct, &viewRct);            /* Do the main thing. */
  1553.  
  1554.     err = noErr;
  1555.     viewCtl = hScrollCtl = vScrollCtl = nil;
  1556.         /* Prepare for various failures. */
  1557.  
  1558.     docID = nil;
  1559.  
  1560.     if (te) {        /* If we were able to create the TextEdit record... */
  1561.  
  1562.         if(gUseTSMTE) {
  1563.             if (!(err = NewTSMDocument(1, supportedInterfaceTypes, &docID, (long)&tsmRec))) {
  1564.                 (*tsmRec)->textH           = te;
  1565.                 (*tsmRec)->preUpdateProc  = nil;
  1566.  
  1567.                 if (!tsmteupp) tsmteupp   = NewTSMTEPostUpdateProc(TSMTEUpdateProc);
  1568.                 (*tsmRec)->postUpdateProc = tsmteupp;
  1569.  
  1570.                 (*tsmRec)->updateFlag     = 0;
  1571.                 (*tsmRec)->refCon         = 0;
  1572.             }
  1573.         }
  1574.  
  1575.         if (mode & cteCenterJustify)
  1576.             TESetAlignment(1, te);
  1577.  
  1578.         if (mode & cteRightJustify)
  1579.             TESetAlignment(-1, te);
  1580.  
  1581.         TEGetStyle(0, &styl, &lh, &a, te);
  1582.         if (styl.tsFont == 1) {
  1583.             styl.tsFont = GetAppFont();
  1584.             styl.tsSize = GetDefFontSize();
  1585.             TESetStyle((doFont | doSize), &styl, false, te);
  1586.         }
  1587.  
  1588.         TEAutoView(true, te);
  1589.             /* Let TextEdit 3.0 do most of the scrolling work. */
  1590.  
  1591.         gDefaultClikLoopUPP = (*te)->clickLoop;
  1592. #if USES68KINLINES
  1593.         (*te)->clickLoop = (ProcPtr)ASMTECLIKLOOP;
  1594. #else
  1595.         if (!gClikLoopUPP)
  1596.             gClikLoopUPP = NewTEClickLoopProc(PPCClikLoop);
  1597.         TESetClickLoop(gClikLoopUPP, te);
  1598. #endif
  1599.  
  1600.         if (!gCDEF) {
  1601.             gCDEF = (cdefRsrcJMPHndl)GetResource('CDEF', (viewID / 16));
  1602.             if (!gCDEF) return(resNotFound);
  1603.  
  1604.             if (!gCTECtlUPP) {
  1605.                 gCTECtlUPP = NewControlDefProc(CTECtl);
  1606.             }
  1607.             (*gCDEF)->jmpAddress = (long)gCTECtlUPP;
  1608.             if (TrapExists(_HWPriv))
  1609.                 FlushInstructionCache();
  1610.                     /* Make sure that instruction caches don't kill us. */
  1611.         }
  1612.  
  1613.         if (mode & cteHScroll) {        /* Caller wants a horizontal scrollbar... */
  1614.             SetRect(&scrollRct, 0, 0, 100, 16);
  1615.             hScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1616.             if (hScrollCtl) {
  1617.                 MoveControl(hScrollCtl, brdrRct.left, brdrRct.bottom - 1);
  1618.                 width = brdrRct.right - brdrRct.left;
  1619.                 if (mode & (cteHScrollLessGrow - cteHScroll))
  1620.                     if (!(mode & cteVScroll))
  1621.                         width -= 15;
  1622.                 SizeControl(hScrollCtl, width, 16);
  1623.                     /* Line the scrollbar up with the borderRct. */
  1624.             }
  1625.             else err = resNotFound;
  1626.         }
  1627.  
  1628.         if (mode & cteVScroll) {        /* Caller wants a vertical scrollbar... */
  1629.             SetRect(&scrollRct, 0, 0, 16, 100);
  1630.             vScrollCtl = NewControl(window, &scrollRct, "\p", vis, 0, 0, 0, scrollBarProc, 0);
  1631.             if (vScrollCtl) {
  1632.                 MoveControl(vScrollCtl, brdrRct.right - 1, brdrRct.top);
  1633.                 height = brdrRct.bottom - brdrRct.top;
  1634.                 if (mode & (cteVScrollLessGrow - cteVScroll))
  1635.                     if (!(mode & cteHScroll))
  1636.                         height -= 15;
  1637.                 SizeControl(vScrollCtl, 16, height);
  1638.                     /* Line the scrollbar up with the borderRct. */
  1639.             }
  1640.             else err = resNotFound;
  1641.         }
  1642.  
  1643.         viewCtl = NewControl(window, &ctlRct, "\p", false, 0, 0, 0, viewID, (long)te);
  1644.             /* Use our custom view cdef.  It's wierd, but it's small. */
  1645.  
  1646.         if (!viewCtl)
  1647.             err = resNotFound;
  1648.         else {
  1649.             if (hScrollCtl)
  1650.                 SetControlReference(hScrollCtl, (long)viewCtl);
  1651.             if (vScrollCtl)
  1652.                 SetControlReference(vScrollCtl, (long)viewCtl);
  1653.             (*viewCtl)->contrlData = nil;
  1654.             teData = (CTEDataHndl)NewHandleClear(sizeof(CTEDataRec));
  1655.             if (teData) {
  1656.                 (*teData)->maxTextLen   = maxTextLen;
  1657.                 (*teData)->newUndo      = true;
  1658.                 (*teData)->mode         = mode;
  1659.                 (*teData)->brdrRect     = brdrRct;
  1660.                 (*teData)->brdrRect     = brdrRct;
  1661.                 if (!(mode & cteNoFastKeys))
  1662.                     (*teData)->fastKeys = GoFast;
  1663.                 (*teData)->docID        = docID;
  1664.                 (*viewCtl)->contrlData  = (Handle)teData;
  1665.             }
  1666.             else {
  1667.                 err = memFullErr;
  1668.                 if (docID)
  1669.                     DeleteTSMDocument(docID);
  1670.             }
  1671.         }
  1672.     }
  1673.     else err = memFullErr;
  1674.  
  1675.     SetPort(oldPort);
  1676.  
  1677.     if (err) {        /* Oops.  Somebody wasn't happy. */
  1678.         if (viewCtl)
  1679.             DisposeControl(viewCtl);
  1680.                 /* This also disposes of TextEdit handle! */
  1681.         else
  1682.             if (te)
  1683.                 TEDispose(te);
  1684.                     /* We have to dispose of the TextEdit handle ourselves if
  1685.                     ** creating the view control failed. */
  1686.  
  1687.         te = nil;        /* Indicate that there is no TextEdit control. */
  1688.  
  1689.         if (hScrollCtl)
  1690.             DisposeControl(hScrollCtl);
  1691.                 /* More clean-up. */
  1692.  
  1693.         if (vScrollCtl)
  1694.             DisposeControl(vScrollCtl);
  1695.                 /* And still more clean-up. */
  1696.     }
  1697.     else {
  1698.         if (mode & cteActive)
  1699.             CTEActivate(true, te);
  1700.  
  1701.         if (vis) ShowStyledControl(viewCtl);        /* Since everything worked, show the control. */
  1702.  
  1703.         if (mode & cteReadOnly) {
  1704.             if (!gNoCaretHookUPP) {
  1705. #if USES68KINLINES
  1706.                 gNoCaretHookUPP = (ProcPtr)ASMNOCARET;
  1707. #else
  1708.                 gNoCaretHookUPP = NewCaretHookProc(PPCNoCaret);
  1709. #endif
  1710.             }
  1711.             (*te)->caretHook = gNoCaretHookUPP;
  1712.                 /* If read-only, then disable caret for this TextEdit control. */
  1713.         }
  1714.  
  1715.         if (teHndl)
  1716.             *teHndl = te;
  1717.         CTEAdjustScrollValues(te);
  1718.             /* Give the scrollbars an initial value.  This is because the
  1719.             ** TextEdit control could have been created with
  1720.             ** destRct.top < viewRct.top or destRct.left < viewRct.left.
  1721.             ** I don't know why anyone would want to, but it is legal.
  1722.             */
  1723.     }
  1724.  
  1725.     return(err);
  1726. }
  1727.  
  1728. static Boolean    GoFast(TEHandle teHndl, EventRecord *event)
  1729. {
  1730. #ifndef __MWERKS__
  1731. #pragma unused (teHndl)
  1732. #endif
  1733.  
  1734.     char    key;
  1735.  
  1736.     if (event->modifiers & cmdKey) return(false);
  1737.     key = event->message & charCodeMask;
  1738.     if (key == chTab) return(false);
  1739.  
  1740.     return(true);
  1741. }
  1742.  
  1743.  
  1744.  
  1745. /*****************************************************************************/
  1746.  
  1747.  
  1748.  
  1749. /* Save the data (if appropriate) so that user can undo. */
  1750.  
  1751. void    CTENewUndo(ControlHandle viewCtl, Boolean alwaysNewUndo)
  1752. {
  1753.     TEHandle        teHndl;
  1754.     CTEDataHndl        teData;
  1755.     Handle            hText, uText;
  1756.     StScrpHandle    hStyl, uStyl;
  1757.  
  1758.     if (!viewCtl) return;
  1759.  
  1760.     teHndl = (TEHandle)GetControlReference(viewCtl);
  1761.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  1762.  
  1763.     if ((!alwaysNewUndo) && (!(*teData)->newUndo)) return;
  1764.         /* If there isn't a new undo to record, then just return. */
  1765.  
  1766.     hText = (*teHndl)->hText;
  1767.     hStyl = CTEGetFullStylScrap(teHndl);
  1768.     uText = (*teData)->undoText;
  1769.     uStyl = (*teData)->undoStyl;
  1770.         /* hText/hStyl is styled text in the TextEdit record that is being edited.  */
  1771.         /* uText/uStyl is the undo data (if any) prior to current edit task. */
  1772.  
  1773.     if (uText) {                /* Dump the old undo info, if any. */
  1774.         DisposeHandle(uText);
  1775.         (*teData)->undoText = nil;
  1776.     }
  1777.     if (uStyl) {
  1778.         DisposeHandle((Handle)uStyl);
  1779.         (*teData)->undoStyl = nil;
  1780.     }
  1781.  
  1782.     if (!hStyl) return;
  1783.         /* Not enough ram to record undo, so leave. */
  1784.  
  1785.     uText = hText;
  1786.     if (HandToHand(&uText)) {            /* Copy the text (if ram available). */
  1787.         DisposeHandle((Handle)hStyl);
  1788.         return;                            /* Not enough ram to record undo. */
  1789.     }
  1790.  
  1791.     (*teData)->undoText     = uText;
  1792.     (*teData)->undoStyl     = hStyl;
  1793.     (*teData)->newUndo      = false;
  1794.     (*teData)->undoSelStart = (*teHndl)->selStart;
  1795.     (*teData)->undoSelEnd   = (*teHndl)->selEnd;
  1796. }
  1797.  
  1798.  
  1799.  
  1800. /*****************************************************************************/
  1801.  
  1802.  
  1803.  
  1804. /* Get the next TextEdit control in the window.  You pass it a control handle
  1805. ** for the view control, or nil to start at the beginning of the window.
  1806. ** It returns both a TextEdit handle and the view control handle for that
  1807. ** TextEdit record.  If none is found, nil is returned.  This allows you to
  1808. ** repeatedly call this function and walk through all the TextEdit controls
  1809. ** in a window. */
  1810.  
  1811. ControlHandle    CTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1812. {
  1813.     short            i;
  1814.     ControlHandle    nextCtl, priorCtl;
  1815.  
  1816.     if (teHndl)
  1817.         *teHndl = nil;
  1818.  
  1819.     if (!window) return(nil);
  1820.     if (!gCDEF)  return(nil);
  1821.  
  1822.     if (dir > 0) {
  1823.         if (!ctl)
  1824.             ctl = ((WindowPeek)window)->controlList;
  1825.         else
  1826.             ctl = (*ctl)->nextControl;
  1827.         while (ctl) {
  1828.             if ((!justActive) || ((*ctl)->contrlVis)) {
  1829.                 if ((!justActive) || ((*ctl)->contrlHilite != 255)) {
  1830.                     if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gCDEF)) {
  1831.                             /* The handle may be locked, which means that the hi-bit
  1832.                             ** may be on, thus invalidating the compare.  Dereference the
  1833.                             ** handles to get rid of this possibility. */
  1834.                         if (teHndl)
  1835.                             *teHndl = (TEHandle)GetControlReference(ctl);
  1836.                         return(ctl);
  1837.                     }
  1838.                 }
  1839.             }
  1840.             ctl = (*ctl)->nextControl;
  1841.         }
  1842.         return(ctl);
  1843.     }
  1844.  
  1845.     nextCtl = ((WindowPeek)window)->controlList;
  1846.     for (i = 1, priorCtl = nil; ;nextCtl = (*nextCtl)->nextControl, ++i) {
  1847.         if ((!nextCtl) || (nextCtl == ctl)) {
  1848.             if (priorCtl)
  1849.                 if (teHndl)
  1850.                     *teHndl = (TEHandle)GetControlReference(priorCtl);
  1851.             return(priorCtl);
  1852.         }
  1853.         if ((!justActive) || ((*nextCtl)->contrlVis)) {
  1854.             if ((!justActive) || ((*nextCtl)->contrlHilite != 255)) {
  1855.                 if (StripAddress((*nextCtl)->contrlDefProc) == StripAddress(gCDEF))
  1856.                     priorCtl = nextCtl;
  1857.             }
  1858.         }
  1859.     }
  1860. }
  1861.  
  1862.  
  1863.  
  1864. static ControlHandle    dummyCTENext(WindowPtr window, TEHandle *teHndl, ControlHandle ctl, short dir, Boolean justActive)
  1865. {
  1866. #ifndef __MWERKS__
  1867. #pragma unused (window, ctl, dir, justActive)
  1868. #endif
  1869.     *teHndl = nil;
  1870.     return(nil);
  1871. }
  1872.  
  1873.  
  1874.  
  1875. /*****************************************************************************/
  1876.  
  1877.  
  1878.  
  1879. /* Return the number of lines of text.  This is because there is a bug in
  1880. ** TextEdit where the number of lines returned is incorrect if the text
  1881. ** ends with a c/r.  This function adjusts for this bug. */
  1882.  
  1883. short    CTENumTextLines(TEHandle teHndl)
  1884. {
  1885.     short    lines;
  1886.     char    *cptr;
  1887.  
  1888.     if (!teHndl) return(0);
  1889.  
  1890.     lines = (*teHndl)->nLines;
  1891.  
  1892.     cptr = *((*teHndl)->hText);        /* Pointer to first TextEdit character. */
  1893.     if (cptr[(*teHndl)->teLength - 1] == kCrChar)
  1894.         ++lines;
  1895.             /* Since nLines isn’t right if the last character is a return,
  1896.             ** check for that case and fix it. */
  1897.  
  1898.     return(lines);
  1899. }
  1900.  
  1901.  
  1902.  
  1903. /*****************************************************************************/
  1904.  
  1905.  
  1906.  
  1907. /* Use this function to print the contents of a TextEdit record.  Pass it a
  1908. ** TextEdit handle, a pointer to a text offset, and a pointer to a rect to
  1909. ** print the text in.  The offset should be initialized to what character
  1910. ** in the TextEdit record you wish to start printing at (most likely 0).
  1911. ** The print function prints as much text as will fit in the rect, and
  1912. ** then updates the offset to tell you what is the first character that didn't
  1913. ** print.  You can then call the print function again with another rect with
  1914. ** this new offset, and it will print the text starting at the new offset.
  1915. ** This method is very useful when a single TextEdit record is longer than a
  1916. ** single page, and you wish the text to break at the end of the page.
  1917. ** The bottom of rect is also updated, along with the offset.  The bottom edge
  1918. ** of the rect is changed to reflect the actual bottom of the text printed.
  1919. ** This is useful because the rect passed in didn't necessarily hold an
  1920. ** integer number of lines of text.  The bottom of the rect is adjusted so
  1921. ** it exactly holds complete lines of text.
  1922. ** It is also possible that the rect could hold substantially more lines of
  1923. ** text than there are remaining.  Again, in this situation, the bottom of
  1924. ** rect is adjusted so that the rect tightly bounds the text printed.
  1925. ** The remaining piece of information passed back is an indicator that the
  1926. ** text through the end of the TextEdit record was printed.  When the end
  1927. ** of the text is reached, the offset for the next text to be printed is
  1928. ** returned as -1.  This indicates that processing of the TextEdit record
  1929. ** is complete. */
  1930.  
  1931. OSErr    CTEPrint(TEHandle teHndl, short *teOffset, Rect *teRct)
  1932. {
  1933.     short            len, offset, numLines, rctHeight, selStart, selEnd, lnum, y, lh;
  1934.     Handle            hText;
  1935.     Rect            keepDestRct, keepViewRct;
  1936.     WindowPtr        printPort;
  1937.     StScrpHandle    fullStyl, partStyl;
  1938.  
  1939.     if (!teHndl) return(noErr);
  1940.  
  1941.     len = (*teHndl)->teLength;
  1942.     if ((offset = *teOffset) >= len) {
  1943.         *teOffset = -1;                    /* We are offset further than we have text. */
  1944.         teRct->bottom = teRct->top;        /* Empty rect, since no text to draw.  */
  1945.         return(noErr);                    /* Just say that we have no more text. */
  1946.     }
  1947.  
  1948.     if (!(hText = NewHandle(len - offset))) return(memFullErr);
  1949.         /* Can't make part-text handle, so leave. */
  1950.  
  1951.     BlockMove((*(*teHndl)->hText) + offset, *hText, len - offset);
  1952.         /* hText now holds all characters after offset. */
  1953.  
  1954.     fullStyl = CTEGetFullStylScrap(teHndl);
  1955.     if (!fullStyl) {
  1956.         DisposeHandle(hText);        /* Couldn't get styles, so clean up and leave. */
  1957.         return(memFullErr);
  1958.     }
  1959.  
  1960.     partStyl = fullStyl;                    /* This assignment tests for styled TE, and if there */
  1961.     if (partStyl) {                            /* is none, then partStyl gets initialized to nil.   */
  1962.  
  1963.         selStart = (*teHndl)->selStart;        /* Get all styles after the offset. */
  1964.         selEnd   = (*teHndl)->selEnd;
  1965.         (*teHndl)->selStart = offset;
  1966.         (*teHndl)->selEnd   = (*teHndl)->teLength;
  1967.         partStyl = TEGetStyleScrapHandle(teHndl);
  1968.         (*teHndl)->selStart = selStart;
  1969.         (*teHndl)->selEnd   = selEnd;
  1970.         if (!partStyl) {
  1971.             DisposeHandle((Handle)fullStyl);
  1972.             DisposeHandle(hText);
  1973.             return(memFullErr);
  1974.         }
  1975.     }
  1976.  
  1977.     keepDestRct = (*teHndl)->destRect;
  1978.     keepViewRct = (*teHndl)->viewRect;
  1979.     gTEWindow   = (*teHndl)->inPort;
  1980.         /* Cache some information from the TextEdit record. */
  1981.  
  1982.     GetPort(&printPort);
  1983.     (*teHndl)->inPort = printPort;
  1984.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  1985.         /* Install the print rect into the TextEdit record so CTESwapText
  1986.         ** recalcs against the print text. */
  1987.  
  1988.     hText = CTESwapText(teHndl, hText, partStyl, false);
  1989.     DisposeHandle((Handle)partStyl);
  1990.         /* We now have all of the text starting at offset formatted correctly in the print rect. */
  1991.  
  1992.     rctHeight = teRct->bottom - teRct->top;
  1993.     numLines  = CTENumTextLines(teHndl);
  1994.     for (y = 0, lnum = 1; lnum <= numLines; ++lnum) {
  1995.         lh = CTEGetLineHeight(teHndl, lnum, nil);
  1996.         if (y + lh > rctHeight) break;
  1997.         y += lh;
  1998.     }
  1999.     teRct->bottom = teRct->top + y;
  2000.     
  2001.     (*teHndl)->destRect = (*teHndl)->viewRect = *teRct;
  2002.         /* We now have the minimum rectangle to hold as much of the text
  2003.         ** as would fit into the rectangle passed in.  The final calc on
  2004.         ** the rect prevents partial lines from being drawn. */
  2005.  
  2006.     TEUpdate(teRct, teHndl);        /* Draw this portion of the text. */
  2007.  
  2008.     if (--lnum >= numLines)
  2009.         *teOffset = -1;
  2010.             /* Printed the last of the text for this record. */
  2011.     else
  2012.         *teOffset = (*teHndl)->lineStarts[lnum] + offset;
  2013.             /* Offset to the first character not printed. */
  2014.  
  2015.     (*teHndl)->inPort   = gTEWindow;
  2016.     gTEWindow           = nil;
  2017.     (*teHndl)->destRect = keepDestRct;
  2018.     (*teHndl)->viewRect = keepViewRct;
  2019.  
  2020.     DisposeHandle(CTESwapText(teHndl, hText, fullStyl, false));
  2021.     DisposeHandle((Handle)fullStyl);
  2022.  
  2023.     return(noErr);            /* Everything worked. */
  2024. }
  2025.  
  2026.  
  2027.  
  2028. /*****************************************************************************/
  2029.  
  2030.  
  2031.  
  2032. /* Return if the TextEdit control is read/write (true) or read-only (false). */
  2033.  
  2034. Boolean    CTEReadOnly(TEHandle teHndl)
  2035. {
  2036.     if (teHndl)
  2037.         if (gNoCaretHookUPP)
  2038.             if ((*teHndl)->caretHook == gNoCaretHookUPP)
  2039.                 return(true);
  2040.  
  2041.     return(false);
  2042. }
  2043.  
  2044.  
  2045.  
  2046. /*****************************************************************************/
  2047.  
  2048.  
  2049.  
  2050. /* Return the control handle for the TextEdit control's scrollbar, either
  2051. ** vertical or horizontal.  If the scrollbar doesn't, nil is returned. */
  2052.  
  2053. ControlHandle    CTEScrollFromTE(TEHandle teHndl, Boolean vertScroll)
  2054. {
  2055.     ControlHandle    viewCtl;
  2056.  
  2057.     if (!(viewCtl = CTEViewFromTE(teHndl))) return(nil);
  2058.  
  2059.     return(CTEScrollFromView(viewCtl, vertScroll));
  2060. }
  2061.  
  2062.  
  2063.  
  2064. /*****************************************************************************/
  2065.  
  2066.  
  2067.  
  2068. /* Return the control handle for the scrollbar related to the view control,
  2069. ** either horizontal or vertical.  If the scrollbar doesn't exist, return nil. */
  2070.  
  2071. ControlHandle    CTEScrollFromView(ControlHandle viewCtl, Boolean vertScroll)
  2072. {
  2073.     ControlHandle    ctl;
  2074.     WindowPtr        window;
  2075.     Boolean            vert;
  2076.  
  2077.     if (!viewCtl) return(nil);
  2078.  
  2079.     window = (*viewCtl)->contrlOwner;
  2080.     ctl    = ((WindowPeek)window)->controlList;
  2081.  
  2082.     for (; ctl;) {
  2083.         if ((ControlHandle)GetControlReference(ctl) == viewCtl) {
  2084.             vert = false;
  2085.             if ((*ctl)->contrlRect.right == (*ctl)->contrlRect.left + 16)
  2086.                 vert = true;
  2087.             if (vert == vertScroll) return(ctl);
  2088.         }
  2089.         ctl = (*ctl)->nextControl;
  2090.     }
  2091.     return(nil);
  2092. }
  2093.  
  2094.  
  2095.  
  2096. /*****************************************************************************/
  2097.  
  2098.  
  2099.  
  2100. /* A TextEdit control can have an optional key filter, which is called whenever
  2101. ** CTEKey() is called.  If you pass in nil, then the filtering is turned off.
  2102. ** This allows individual TextEdit controls to handle their own filtering.
  2103. ** The filter procedure is of the form:
  2104. **     Boolean (*CTEKeyFilterProcPtr)(TEHandle teHndl, EventRecord *event, short *handled);
  2105. ** If true is returned, then CTEKey() is aborted, and the value in "handled" is
  2106. ** returned.  By having a separate abort value and return value, you can determine
  2107. ** if processing of the event should be continued or not, independent of whether
  2108. ** or not you aborted CTEKey(). */
  2109.  
  2110. void    CTESetKeyFilter(TEHandle teHndl, CTEKeyFilterProcPtr proc)
  2111. {
  2112.     ControlHandle    viewCtl;
  2113.     CTEDataHndl        teData;
  2114.  
  2115.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2116.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2117.     (*teData)->keyFilter = proc;
  2118. }
  2119.  
  2120.  
  2121.  
  2122. /*****************************************************************************/
  2123.  
  2124.  
  2125.  
  2126. void    CTESetFastKeys(TEHandle teHndl, CTEFastKeysProcPtr proc)
  2127. {
  2128.     ControlHandle    viewCtl;
  2129.     CTEDataHndl        teData;
  2130.  
  2131.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2132.     teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2133.     (*teData)->fastKeys = proc;
  2134. }
  2135.  
  2136.  
  2137.  
  2138. /*****************************************************************************/
  2139.  
  2140.  
  2141.  
  2142. /* Select a range of text.  TESetSelect can't be used alone because it doesn't
  2143. ** update the scrollbars.  This function calls TESetSelect, and then fixes up
  2144. ** the scrollbars. */
  2145.  
  2146. void    CTESetSelect(short start, short end, TEHandle teHndl)
  2147. {
  2148.     WindowPtr        oldPort;
  2149.     ControlHandle    viewCtl;
  2150.     CTEDataHndl        teData;
  2151.  
  2152.     if (teHndl) {
  2153.         GetPort(&oldPort);
  2154.         SetPort((*teHndl)->inPort);
  2155.         TESetSelect(start, end, teHndl);
  2156.         CTEAdjustScrollValues(teHndl);
  2157.         viewCtl = CTEViewFromTE(teHndl);
  2158.         if (viewCtl) {
  2159.             teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2160.             (*teData)->newUndo = true;
  2161.         }
  2162.         SetPort(oldPort);
  2163.     }
  2164. }
  2165.  
  2166.  
  2167.  
  2168. static void    dummyCTESetSelect(short start, short end, TEHandle teHndl)
  2169. {
  2170. #ifndef __MWERKS__
  2171. #pragma unused (start, end, teHndl)
  2172. #endif
  2173. }
  2174.  
  2175.  
  2176.  
  2177. /*****************************************************************************/
  2178.  
  2179.  
  2180.  
  2181. /* Show the designated TextEdit control and related scrollbars. */
  2182.  
  2183. void    CTEShow(TEHandle teHndl)
  2184. {
  2185.     ControlHandle    viewCtl, scrollCtl;
  2186.     short            i;
  2187.  
  2188.     viewCtl = CTEViewFromTE(teHndl);
  2189.     if (viewCtl) {
  2190.         ShowStyledControl(viewCtl);
  2191.         for (i = 0; i < 2; i++) {
  2192.             scrollCtl = CTEScrollFromView(viewCtl, i);
  2193.             if (scrollCtl)
  2194.                 ShowStyledControl(scrollCtl);
  2195.         }
  2196.     }
  2197. }
  2198.  
  2199.  
  2200.  
  2201. /*****************************************************************************/
  2202.  
  2203.  
  2204.  
  2205. /* This function is used to resize a TextEdit control.  Pass it the TextEdit
  2206. ** record to resize, plus the new horizontal and vertical size.  It will
  2207. ** resize the TextEdit control, realign the text, if necessary, plus it will
  2208. ** resize and adjust any scrollbars the TextEdit control may have.  All areas
  2209. ** that need updating are cleared and invalidated. */
  2210.  
  2211. void    CTESize(TEHandle teHndl, short newH, short newV, Boolean newDest)
  2212. {
  2213.     WindowPtr        oldPort;
  2214.     Rect            viewRct, brdrRct, teViewRct, oldTeViewRct, rct;
  2215.     short            i, dx, dy, mode, hScroll, vScroll;
  2216.     ControlHandle    viewCtl, ctl[2];
  2217.     CTEDataHndl        teData;
  2218.     RgnHandle        rgn1, rgn2;
  2219.     char            vis;
  2220.  
  2221.     if (!(viewCtl = CTEViewFromTE(teHndl))) return;
  2222.  
  2223.     GetPort(&oldPort);
  2224.     SetPort((*teHndl)->inPort);
  2225.  
  2226.     viewRct = (*viewCtl)->contrlRect;
  2227.     vis     = (*viewCtl)->contrlVis;
  2228.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2229.     brdrRct = (*teData)->brdrRect;
  2230.     mode    = (*teData)->mode;
  2231.  
  2232.     dx = newH - (viewRct.right  - viewRct.left);
  2233.     dy = newV - (viewRct.bottom - viewRct.top);
  2234.     if ((!dx) && (!dy)) return;
  2235.  
  2236.     hScroll = (mode & cteHScroll) ? 1 : 0;
  2237.     vScroll = (mode & cteVScroll) ? 1 : 0;
  2238.         /* Get enough info to determine if we need to fix the scrollbar sizes. */
  2239.  
  2240.     rct = viewRct;                /* Erase all of the old list control and scrollbars. */
  2241.     if (!EmptyRect(&brdrRct))
  2242.         UnionRect(&rct, &brdrRct, &rct);
  2243.     if (vScroll)
  2244.         rct.right += 15;
  2245.     if (hScroll)
  2246.         rct.bottom += 15;
  2247.     if (mode & cteShowActive)
  2248.         InsetRect(&rct, -4, -4);
  2249.     if (vis) {
  2250.         EraseRect(&rct);
  2251.         InvalRect(&rct);
  2252.     }
  2253.  
  2254.     for (i = 0; i < 2; ++i) {
  2255.         ctl[i] = CTEScrollFromView(viewCtl, i);
  2256.         if (ctl[i]) {
  2257.             rct = (*ctl[i])->contrlRect;
  2258.             if (i) {
  2259.                 HideControl(ctl[i]);
  2260.                 SizeControl(ctl[i], rct.right - rct.left, rct.bottom - rct.top + dy);
  2261.                 MoveControl(ctl[i], rct.left + dx, rct.top);
  2262.             }
  2263.             else {
  2264.                 HideControl(ctl[i]);
  2265.                 SizeControl(ctl[i], rct.right - rct.left + dx, rct.bottom - rct.top);
  2266.                 MoveControl(ctl[i], rct.left, rct.top + dy);
  2267.             }
  2268.         }
  2269.     }        /* Reposition the scrollbars, if we have any. */
  2270.  
  2271.     if (vis) InvalRect(&viewRct);        /* Resize our view control. */
  2272.     viewRct.right  += dx;
  2273.     viewRct.bottom += dy;
  2274.     (*viewCtl)->contrlRect = viewRct;
  2275.     if (vis) InvalRect(&viewRct);
  2276.  
  2277.     if (vis) InvalRect(&brdrRct);        /* Resize our border rect. */
  2278.     brdrRct.right  += dx;
  2279.     brdrRct.bottom += dy;
  2280.     (*teData)->brdrRect = brdrRct;
  2281.     if (vis) InvalRect(&brdrRct);
  2282.  
  2283.     teViewRct = oldTeViewRct = (*teHndl)->viewRect;        /* Resize TextEdit viewRect. */
  2284.     teViewRct.right  += dx;
  2285.     teViewRct.bottom += dy;
  2286.     (*teHndl)->viewRect = teViewRct;
  2287.  
  2288.     if (newDest) {        /* Resize TextEdit destRect, if so indicated. */
  2289.         (*teHndl)->destRect.right  += dx;
  2290.         (*teHndl)->destRect.bottom += dy;
  2291.         TECalText(teHndl);
  2292.         if (vis) {
  2293.             EraseRect(&oldTeViewRct);        /* Redraw the whole thing if destRect changes. */
  2294.             InvalRect(&oldTeViewRct);
  2295.         }
  2296.     }
  2297.  
  2298.     if (vis) {
  2299.         rgn1 = NewRgn();
  2300.         rgn2 = NewRgn();
  2301.         RectRgn(rgn1, &oldTeViewRct);        /* Clear old areas if we are shrinking. */
  2302.         RectRgn(rgn2, &teViewRct);
  2303.         DiffRgn(rgn1, rgn2, rgn2);
  2304.         EraseRgn(rgn2);
  2305.         InvalRgn(rgn2);
  2306.         RectRgn(rgn2, &teViewRct);            /* Update new areas if we are growing. */
  2307.         DiffRgn(rgn2, rgn1, rgn2);
  2308.         InvalRgn(rgn2);
  2309.         DisposeRgn(rgn1);
  2310.         DisposeRgn(rgn2);
  2311.     }
  2312.  
  2313.     if (vis)
  2314.         for (i = 0; i < 2; ++i)
  2315.             if (ctl[i])
  2316.                 ShowStyledControl(ctl[i]);
  2317.                     /* Show the controls in their new position. */
  2318.  
  2319.     if (mode & (cteVScrollLessGrow - cteVScroll + cteHScrollLessGrow - cteHScroll)) {
  2320.         rct = viewRct;
  2321.         rct.top  = rct.bottom - 16;
  2322.         rct.left = rct.right - 16;
  2323.         if (mode & (cteVScrollLessGrow - cteVScroll))
  2324.             OffsetRect(&rct, 16, 0);
  2325.         if (mode & (cteHScrollLessGrow - cteHScroll))
  2326.             OffsetRect(&rct, 0, 16);
  2327.         if (vis) {
  2328.             EraseRect(&rct);
  2329.             InvalRect(&rct);
  2330.         }
  2331.     }
  2332.  
  2333.     CTEAdjustTEBottom(teHndl);
  2334.     CTEAdjustScrollValues(teHndl);
  2335.  
  2336.     SetPort(oldPort);
  2337. }
  2338.  
  2339.  
  2340.  
  2341. /*****************************************************************************/
  2342.  
  2343.  
  2344.  
  2345. /* Swap the TextEdit text handle with the text handle passed in. */
  2346.  
  2347. Handle    CTESwapText(TEHandle teHndl, Handle newText, StScrpHandle styl, Boolean update)
  2348. {
  2349.     WindowPtr        oldPort;
  2350.     Handle            oldText;
  2351.     Rect            destRct, viewRct;
  2352.     TextStyle        srun;
  2353.     ScrpSTElement    s;
  2354.     ControlHandle    viewCtl;
  2355.     CTEDataHndl        teData;
  2356.     RgnHandle        oldClip, newClip;
  2357.  
  2358.     if (!teHndl) return(nil);
  2359.  
  2360.     GetPort(&oldPort);
  2361.     SetPort((*teHndl)->inPort);
  2362.  
  2363.     oldText = (*teHndl)->hText;
  2364.     HandToHand(&oldText);
  2365.  
  2366.     HLock(newText);
  2367.     TESetText(*newText, 0, teHndl);                            /* Make there be only 1 style run. */
  2368.     TESetText(*newText, GetHandleSize(newText), teHndl);    /* Put the correct text in the record. */
  2369.     DisposeHandle(newText);
  2370.  
  2371.     viewCtl = CTEViewFromTE(teHndl);
  2372.     teData  = (CTEDataHndl)(*viewCtl)->contrlData;
  2373.     if (!((*teData)->mode & cteRightJustify)) {
  2374.         if (!(*viewCtl)->contrlVis) {
  2375.             GetClip(oldClip = NewRgn());
  2376.             SetClip(newClip = NewRgn());
  2377.         }
  2378.         TESetSelect(0, 0, teHndl);
  2379.         if (!(*viewCtl)->contrlVis) {
  2380.             SetClip(oldClip);
  2381.             DisposeRgn(oldClip);
  2382.             DisposeRgn(newClip);
  2383.         }
  2384.     }
  2385.  
  2386.     if (styl) {
  2387.         CTESetStylScrap(0, (*teHndl)->teLength, styl, teHndl);        /* Apply style to all text. */
  2388.         if ((*teHndl)->selStart)                                    /* Apply style to caret loc. */
  2389.             s = (*styl)->scrpStyleTab[0];
  2390.         else
  2391.             s = (*styl)->scrpStyleTab[(*styl)->scrpNStyles - 1];
  2392.         srun.tsFont  = s.scrpFont;
  2393.         srun.tsFace  = s.scrpFace;
  2394.         srun.tsSize  = s.scrpSize;
  2395.         srun.tsColor = s.scrpColor;
  2396.         TESetStyle(doAll, &srun, false, teHndl);
  2397.     }
  2398.  
  2399.     GetClip(oldClip = NewRgn());        /* Force the nullStyle to become active. */
  2400.     SetClip(newClip = NewRgn());        /* This also resizes the caret to reflect nullStyle size. */
  2401.     TEKey(' ', teHndl);
  2402.     TEKey(8, teHndl);
  2403.     SetClip(oldClip);
  2404.     DisposeRgn(oldClip);
  2405.     DisposeRgn(newClip);
  2406.  
  2407.     TECalText(teHndl);
  2408.  
  2409.     if (update) {
  2410.         destRct = (*teHndl)->destRect;
  2411.         viewRct = (*teHndl)->viewRect;
  2412.  
  2413.         OffsetRect(&destRct,
  2414.             viewRct.left - destRct.left,
  2415.             viewRct.top  - destRct.top);
  2416.  
  2417.         (*teHndl)->destRect = destRct;
  2418.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2419.  
  2420.         CTEUpdate(teHndl, CTEViewFromTE(teHndl), false);
  2421.     }
  2422.  
  2423.     CTEAdjustTEBottom(teHndl);        /* Fix these things up, whether showing or not. */
  2424.     CTEAdjustScrollValues(teHndl);
  2425.  
  2426.     SetPort(oldPort);
  2427.     return(oldText);
  2428. }
  2429.  
  2430.  
  2431.  
  2432. /*****************************************************************************/
  2433.  
  2434.  
  2435.  
  2436. /* Return information for the currently active TextEdit control.  The currently
  2437. ** active TextEdit control is stored in gActiveTEHndl, and can be accessed
  2438. ** directly.  If gActiveTEHndl is nil, then there is no currently active one.
  2439. ** The information that we return is the viewRect and window of the active
  2440. ** TextEdit control.  This is information that could be gotten directly, but
  2441. ** this call makes it a little more convenient. */
  2442.  
  2443. WindowPtr    CTETargetInfo(TEHandle *teHndl, Rect *teView)
  2444. {
  2445.     if (teView)
  2446.         SetRect(teView, 0, 0, 0, 0);
  2447.  
  2448.     if (teHndl)
  2449.         *teHndl = gActiveTEHndl;
  2450.  
  2451.     if (!gActiveTEHndl) return(nil);
  2452.  
  2453.     if (teView)
  2454.         *teView = (*gActiveTEHndl)->viewRect;
  2455.  
  2456.     return((*gActiveTEHndl)->inPort);
  2457. }
  2458.  
  2459.  
  2460.  
  2461. /*****************************************************************************/
  2462.  
  2463.  
  2464.  
  2465. /* Perform an undo function for the TextEdit control. */
  2466.  
  2467. ControlHandle    CTEUndo(void)
  2468. {
  2469.     TEHandle        teHndl;
  2470.     ControlHandle    viewCtl;
  2471.     CTEDataHndl        teData;
  2472.     Handle            hText, uText;
  2473.     StScrpHandle    hStyl, uStyl;
  2474.     short            oldStart, oldEnd;
  2475.  
  2476.     if (!(teHndl = gActiveTEHndl)) return(nil);
  2477.  
  2478.     viewCtl = CTEViewFromTE(teHndl);
  2479.     if (viewCtl) {
  2480.         oldStart = (*teHndl)->selStart;
  2481.         oldEnd   = (*teHndl)->selEnd;
  2482.  
  2483.         (*teHndl)->selStart = (*teHndl)->selEnd = 0;
  2484.  
  2485.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2486.         hText  = (*teHndl)->hText;
  2487.         uText  = (*teData)->undoText;
  2488.         if (!uText) return(nil);        /* There is no undo yet.  Getting called in this state is
  2489.                                         ** actually an error, but we check, just in case. */
  2490.  
  2491.         hStyl = CTEGetFullStylScrap(teHndl);
  2492.         uStyl = (*teData)->undoStyl;
  2493.  
  2494.         (*teData)->undoText = CTESwapText(teHndl, (*teData)->undoText, uStyl, false);
  2495.         DisposeHandle((Handle)uStyl);
  2496.         (*teData)->undoStyl = hStyl;
  2497.  
  2498.         CTEUpdate(teHndl, viewCtl, false);
  2499.         TESetSelect((*teData)->undoSelStart, (*teData)->undoSelEnd, teHndl);
  2500.         CTEAdjustTEBottom(teHndl);
  2501.         CTEAdjustScrollValues(teHndl);
  2502.  
  2503.         (*teData)->newUndo      = true;
  2504.         (*teData)->undoSelStart = oldStart;
  2505.         (*teData)->undoSelEnd   = oldEnd;
  2506.     }
  2507.  
  2508.     return(viewCtl);
  2509. }
  2510.  
  2511.  
  2512.  
  2513. /*****************************************************************************/
  2514.  
  2515.  
  2516.  
  2517. /* Draw the TextEdit control and frame. */
  2518.  
  2519. void    CTEUpdate(TEHandle teHndl, ControlHandle ctl, Boolean justShowActive)
  2520. {
  2521.     WindowPtr    oldPort, tePort;
  2522.     Rect        viewRct, brdrRct, rr;
  2523.     CTEDataHndl    teData;
  2524.     short        mode;
  2525.  
  2526.     if (teHndl) {
  2527.         if ((*ctl)->contrlVis) {
  2528.  
  2529.             GetPort(&oldPort);
  2530.             SetPort(tePort = (*teHndl)->inPort);
  2531.  
  2532.             teData  = (CTEDataHndl)(*ctl)->contrlData;
  2533.             mode    = (*teData)->mode;
  2534.             viewRct = (*teHndl)->viewRect;
  2535.             brdrRct = (*teData)->brdrRect;
  2536.  
  2537.             if (!justShowActive) {
  2538.                 if (!EmptyRect(&brdrRct)) {
  2539.                     if (!(mode & cteNoBorder)) {
  2540.                         FrameRect(&brdrRct);
  2541.                         InsetRect(&brdrRct, 1, 1);
  2542.                         EraseRect(&brdrRct);
  2543.                         InsetRect(&brdrRct, -1, -1);
  2544.                     }
  2545.                     else {
  2546.                         rr = brdrRct;
  2547.                         if (mode & cteVScroll) --rr.bottom;
  2548.                         if (mode & cteHScroll) --rr.right;
  2549.                         EraseRect(&rr);
  2550.                     }
  2551.                 }
  2552.                 else EraseRect(&viewRct);
  2553.                 TEUpdate(&viewRct, teHndl);
  2554.             }
  2555.     
  2556.             if (mode & cteShowActive) {
  2557.                 if (!EmptyRect(&brdrRct)) {
  2558.                     InsetRect(&brdrRct, -3, -3);
  2559.                     if (mode & cteVScroll)
  2560.                         brdrRct.right  += 15;
  2561.                     if (mode & cteHScroll)
  2562.                         brdrRct.bottom += 15;
  2563.                     if ((!((WindowPeek)tePort)->hilited) || (teHndl != gActiveTEHndl))
  2564.                         PenPat((ConstPatternParam)&qd.white);
  2565.                     PenSize(2, 2);
  2566.                     FrameRect(&brdrRct);
  2567.                     InsetRect(&brdrRct, 2, 2);
  2568.                     PenSize(1, 1);
  2569.                     PenPat((ConstPatternParam)&qd.white);
  2570.                     FrameRect(&brdrRct);
  2571.                     PenNormal();
  2572.                 }
  2573.             }
  2574.  
  2575.             SetPort(oldPort);
  2576.         }
  2577.     }
  2578. }
  2579.  
  2580.  
  2581.  
  2582. /*****************************************************************************/
  2583.  
  2584.  
  2585.  
  2586. /* Return the control handle for the view control that owns the TextEdit
  2587. ** record.  Use this to find the view to do customizations such as changing
  2588. ** the update procedure for this TextEdit control. */
  2589.  
  2590. ControlHandle    CTEViewFromTE(TEHandle teHndl)
  2591. {
  2592.     WindowPtr        window;
  2593.     ControlHandle    viewCtl;
  2594.     TEHandle        te;
  2595.  
  2596.     if (!teHndl) return(nil);
  2597.  
  2598.     if (!(window = gTEWindow))
  2599.         window = (WindowPtr)(*teHndl)->inPort;
  2600.  
  2601.     for (viewCtl = nil;;) {
  2602.  
  2603.         viewCtl = CTENext(window, &te, viewCtl, 1, false);
  2604.         if ((!viewCtl) || (te == teHndl)) return(viewCtl);
  2605.     }
  2606. }
  2607.  
  2608.  
  2609.  
  2610. static ControlHandle    dummyCTEViewFromTE(TEHandle teHndl)
  2611. {
  2612. #ifndef __MWERKS__
  2613. #pragma unused (teHndl)
  2614. #endif
  2615.     return(nil);
  2616. }
  2617.  
  2618.  
  2619.  
  2620. /*****************************************************************************/
  2621.  
  2622.  
  2623.  
  2624. /* Call this when a window with TextEdit controls is being activated.  This
  2625. ** will make the TextEdit control that was last active in this window the
  2626. ** active TextEdit control again. */
  2627.  
  2628. TEHandle    CTEWindActivate(WindowPtr window, Boolean displayIt)
  2629. {
  2630.     short            hilite, scrollNum;
  2631.     ControlHandle    viewCtl, scrollCtl;
  2632.     TEHandle        te;
  2633.     CTEDataHndl        teData;
  2634.  
  2635.     if (!window) return(nil);
  2636.  
  2637.     hilite = 255;
  2638.     if (((WindowPeek)window)->hilited)
  2639.         hilite = 0;
  2640.  
  2641.     for (viewCtl = nil; (viewCtl = CTENext(window, &te, viewCtl, 1, true)) != nil;) {
  2642.  
  2643.         teData = (CTEDataHndl)(*viewCtl)->contrlData;
  2644.         if (!((*teData)->mode & cteActive)) continue;
  2645.  
  2646.         if (displayIt) {
  2647.  
  2648.             if (!hilite)
  2649.                 CTEActivate(true, te);
  2650.             else
  2651.                 CTEActivate(false, te);
  2652.  
  2653.             for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2654.                 scrollCtl = CTEScrollFromTE(te, scrollNum);
  2655.                 if (scrollCtl)
  2656.                     HiliteControl(scrollCtl, hilite);
  2657.             }
  2658.         }
  2659.  
  2660.         if (hilite)
  2661.             te = nil;
  2662.  
  2663.         return(te);
  2664.     }
  2665.  
  2666.     return(nil);
  2667. }
  2668.  
  2669.  
  2670.  
  2671. static TEHandle    dummyCTEWindActivate(WindowPtr window, Boolean displayIt)
  2672. {
  2673. #ifndef __MWERKS__
  2674. #pragma unused (window, displayIt)
  2675. #endif
  2676.  
  2677.     return(nil);
  2678. }
  2679.  
  2680.  
  2681.  
  2682. /*****************************************************************************/
  2683.  
  2684.  
  2685.  
  2686. /* This function is called after an edit to make sure that there is no extra
  2687. ** white space at the bottom of the viewRect.  If there are blank lines at
  2688. ** the bottom of the viewRect, and there is text scrolled off the top of the
  2689. ** viewRect, then the TextEdit control is scrolled to fill this space, or as
  2690. ** much of it as possible. */
  2691.  
  2692. void    CTEAdjustTEBottom(TEHandle teHndl)
  2693. {
  2694.     Rect    destRct, viewRct;
  2695.     short    botDiff, topDiff;
  2696.  
  2697.     destRct = (*teHndl)->destRect;
  2698.     viewRct = (*teHndl)->viewRect;
  2699.     destRct.bottom = destRct.top + CTEDocHeight(teHndl);
  2700.  
  2701.     botDiff = viewRct.bottom - destRct.bottom;
  2702.  
  2703.     if (botDiff > 0) {
  2704.         topDiff = viewRct.top - destRct.top;
  2705.         if (botDiff > topDiff)
  2706.             botDiff = topDiff;
  2707.         if (botDiff)
  2708.             TEScroll(0, botDiff, teHndl);
  2709.     }
  2710. }
  2711.  
  2712.  
  2713.  
  2714. /*****************************************************************************/
  2715.  
  2716.  
  2717.  
  2718. /* Bring the scrollbar values up to date with the current document position
  2719. ** and length. */
  2720.  
  2721. void    CTEAdjustScrollValues(TEHandle teHndl)
  2722. {
  2723.     short            scrollNum;
  2724.     ControlHandle    scrollCtl;
  2725.  
  2726.     for (scrollNum = 0; scrollNum < 2; ++scrollNum) {
  2727.         scrollCtl = CTEScrollFromTE(teHndl, scrollNum);
  2728.         if (scrollCtl)
  2729.             AdjustOneScrollValue(teHndl, scrollCtl, scrollNum);
  2730.     }
  2731. }
  2732.  
  2733.  
  2734.  
  2735. /*****************************************************************************/
  2736.  
  2737.  
  2738.  
  2739. StScrpHandle    CTEGetFullStylScrap(TEHandle teHndl)
  2740. {
  2741.     short            selStart, selEnd;
  2742.     StScrpHandle    styl;
  2743.  
  2744.     selStart = (*teHndl)->selStart;
  2745.     selEnd   = (*teHndl)->selEnd;
  2746.  
  2747.     (*teHndl)->selStart = 0;
  2748.     (*teHndl)->selEnd   = (*teHndl)->teLength;
  2749.  
  2750.     styl = TEGetStyleScrapHandle(teHndl);
  2751.  
  2752.     (*teHndl)->selStart = selStart;
  2753.     (*teHndl)->selEnd   = selEnd;
  2754.  
  2755.     return(styl);
  2756. }
  2757.  
  2758.  
  2759.  
  2760. /*****************************************************************************/
  2761.  
  2762.  
  2763.  
  2764. void    CTESetStylScrap(short begRng, short endRng, StScrpHandle styles, TEHandle teHndl)
  2765. {
  2766.     short            n, i, b, e, selStart, selEnd;
  2767.     ScrpSTElement    styl, s;
  2768.     TextStyle        srun;
  2769.     TEStyleHandle    shndl;
  2770.  
  2771.     if (!styles) return;
  2772.  
  2773.     shndl = TEGetStyleHandle(teHndl);
  2774.  
  2775.     selStart = (*teHndl)->selStart;
  2776.     selEnd   = (*teHndl)->selEnd;
  2777.  
  2778.     n = (*styles)->scrpNStyles;
  2779.  
  2780.     for (i = 0; i < n;) {
  2781.         styl = (*styles)->scrpStyleTab[i++];
  2782.         b  = styl.scrpStartChar;
  2783.         if (i == n)
  2784.             e = endRng;
  2785.         else {
  2786.             s = (*styles)->scrpStyleTab[i];
  2787.             e = s.scrpStartChar;
  2788.         }
  2789.         if (b >= endRng) break;            /* We're past the range for style application. */
  2790.         if (e <= begRng) continue;        /* We're not to the range for style application. */
  2791.  
  2792.         if (b < begRng) b = begRng;        /* Clip to range for style application. */
  2793.         if (e > endRng) e = endRng;
  2794.  
  2795.         if (b < e) {
  2796.             srun.tsFont  = styl.scrpFont;
  2797.             srun.tsFace  = styl.scrpFace;
  2798.             srun.tsSize  = styl.scrpSize;
  2799.             srun.tsColor = styl.scrpColor;
  2800.             (*teHndl)->selStart = b;
  2801.             (*teHndl)->selEnd   = e;
  2802.             TESetStyle(doAll, &srun, false, teHndl);
  2803.             TECalText(teHndl);
  2804.         }
  2805.     }
  2806.  
  2807.     (*teHndl)->selStart = selStart;
  2808.     (*teHndl)->selEnd   = selEnd;
  2809. }
  2810.  
  2811.  
  2812.  
  2813. /*****************************************************************************/
  2814.  
  2815.  
  2816.  
  2817. short    CTEGetLineNum(TEHandle te, short offset)
  2818. {
  2819.     short    i;
  2820.  
  2821.     for (i = 0; i < (*te)->nLines; ++i)
  2822.         if ((*te)->lineStarts[i] > offset)
  2823.             break;
  2824.  
  2825.     return(i);
  2826. }
  2827.  
  2828.  
  2829.  
  2830. /*****************************************************************************/
  2831.  
  2832.  
  2833.  
  2834. short    CTEGetLineHeight(TEHandle te, short lineNum, short *ascent)
  2835. {
  2836.     TEStyleHandle    tes;
  2837.     LHHandle        lhh;
  2838.  
  2839.     tes = *(TEStyleHandle *)&((*te)->txFont);
  2840.     lhh = (*tes)->lhTab;
  2841.  
  2842.     if (ascent) *ascent = (*lhh)[lineNum - 1].lhAscent;
  2843.     return((*lhh)[--lineNum].lhHeight);
  2844. }
  2845.  
  2846.  
  2847.  
  2848. /*****************************************************************************/
  2849.  
  2850.  
  2851.  
  2852. void    CTEGetPStr(ControlHandle ctl, StringPtr pstr)
  2853. {
  2854.     TEHandle        te;
  2855.     unsigned short    len;
  2856.  
  2857.     if (!ctl) return;
  2858.     te = (TEHandle)GetControlReference(ctl);
  2859.     if (!te) return;
  2860.  
  2861.     len = (*te)->teLength;
  2862.     if (len > 255) len = 255;
  2863.  
  2864.     BlockMove(*(*te)->hText, pstr + 1, *pstr = len);
  2865. }
  2866.  
  2867.  
  2868.  
  2869. /*****************************************************************************/
  2870.  
  2871.  
  2872.  
  2873. void    CTEPutPStr(ControlHandle ctl, StringPtr pstr)
  2874. {
  2875.     CTESetPStr(ctl, pstr);
  2876. }
  2877.  
  2878.  
  2879.  
  2880. /*****************************************************************************/
  2881.  
  2882.  
  2883.  
  2884. void    CTESetPStr(ControlHandle ctl, StringPtr pstr)
  2885. {
  2886.     TEHandle    te;
  2887.     Handle        h;
  2888.  
  2889.     if (!ctl) return;
  2890.     te = (TEHandle)GetControlReference(ctl);
  2891.     if (!te) return;
  2892.  
  2893.     h = NewHandle(pstr[0]);
  2894.     if (h) {
  2895.         BlockMove(pstr + 1, *h, pstr[0]);
  2896.         DisposeHandle(CTESwapText(te, h, nil, true));
  2897.     }
  2898. }
  2899.  
  2900.  
  2901.  
  2902. /*****************************************************************************/
  2903. /*****************************************************************************/
  2904.  
  2905.  
  2906.  
  2907. static pascal void    VActionProc(ControlHandle scrollCtl, short part)
  2908. {
  2909.     short        delta, value, teOffset;
  2910.     short        oldValue, max, lh, as;
  2911.     TEHandle    te;
  2912.     TextStyle    styl;
  2913.     
  2914.     if (part) {                        /* If it was actually in the control. */
  2915.  
  2916.         te = gActiveTEHndl;
  2917.         TEGetStyle((*te)->selStart, &styl, &lh, &as, te);
  2918.         switch (part) {
  2919.             case inUpButton:
  2920.             case inDownButton:        /* One line. */
  2921.                 delta = lh;
  2922.                 break;
  2923.             case inPageUp:            /* One page. */
  2924.             case inPageDown:
  2925.                 delta = (*te)->viewRect.bottom - (*te)->viewRect.top;
  2926.                 if (delta > lh)
  2927.                     delta -= lh;
  2928.                 break;
  2929.         }
  2930.         if ( (part == inUpButton) || (part == inPageUp) )
  2931.             delta = -delta;        /* Reverse direction for an upper. */
  2932.  
  2933.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  2934.         if (value < 0)
  2935.             value = 0;
  2936.         if (value > (max = GetControlMaximum(scrollCtl)))
  2937.             value = max;
  2938.  
  2939.         if (value != oldValue) {
  2940.             SetControlValue(scrollCtl, value);
  2941.             teOffset = (*te)->viewRect.top - (*te)->destRect.top;
  2942.             if (value -= teOffset)
  2943.                 TEScroll(0, -value, te);
  2944.         }
  2945.     }
  2946. }
  2947.  
  2948.  
  2949.  
  2950. /*****************************************************************************/
  2951.  
  2952.  
  2953.  
  2954. static pascal void    HActionProc(ControlHandle scrollCtl, short part)
  2955. {
  2956.     short        delta, value, teOffset;
  2957.     short        oldValue, max;
  2958.     TEHandle    te;
  2959.     
  2960.     if (part) {                        /* If it was actually in the control. */
  2961.  
  2962.         te = gActiveTEHndl;
  2963.         switch (part) {
  2964.             case inUpButton:
  2965.             case inDownButton:        /* One line. */
  2966.                 delta = 16;
  2967.                 break;
  2968.             case inPageUp:            /* One page. */
  2969.             case inPageDown:
  2970.                 delta = (*te)->viewRect.right - (*te)->viewRect.left;
  2971.                 if (delta > 16)
  2972.                     delta -= 16;
  2973.                 break;
  2974.         }
  2975.         if ( (part == inUpButton) || (part == inPageUp) )
  2976.             delta = -delta;        /* Reverse direction for an upper. */
  2977.  
  2978.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  2979.         if (value < 0)
  2980.             value = 0;
  2981.         if (value > (max = GetControlMaximum(scrollCtl)))
  2982.             value = max;
  2983.  
  2984.         if (value != oldValue) {
  2985.             SetControlValue(scrollCtl, value);
  2986.             teOffset = (*te)->viewRect.left - (*te)->destRect.left;
  2987.             if (value -= teOffset)
  2988.                 TEScroll(-value, 0, te);
  2989.         }
  2990.     }
  2991. }
  2992.  
  2993.  
  2994.  
  2995. /*****************************************************************************/
  2996.  
  2997.  
  2998.  
  2999. /* Bring one scrollbar value up to date with the current document position
  3000. ** and length. */
  3001.  
  3002. static void    AdjustOneScrollValue(TEHandle teHndl, ControlHandle ctl, Boolean vert)
  3003. {
  3004.     Boolean    front;
  3005.     short    textPix, viewPix;
  3006.     short    max, oldMax, value, oldValue;
  3007.  
  3008.     front = ((WindowPeek)(*ctl)->contrlOwner)->hilited;
  3009.  
  3010.     oldValue = GetControlValue(ctl);
  3011.     oldMax   = GetControlMaximum(ctl);
  3012.  
  3013.     if (vert) {
  3014.         textPix = CTEDocHeight(teHndl);
  3015.         viewPix = (*teHndl)->viewRect.bottom - (*teHndl)->viewRect.top;
  3016.     }
  3017.     else {
  3018.         textPix = (*teHndl)->destRect.right - (*teHndl)->destRect.left;
  3019.         viewPix = (*teHndl)->viewRect.right - (*teHndl)->viewRect.left;
  3020.     }
  3021.     max = textPix - viewPix;
  3022.  
  3023.     if (max < 0)
  3024.         max = 0;
  3025.     if (max != oldMax) {
  3026.         if (front)
  3027.             SetControlMaximum(ctl, max);
  3028.         else
  3029.             (*ctl)->contrlMax = max;
  3030.     }
  3031.  
  3032.     if (vert)
  3033.         value = (*teHndl)->viewRect.top  - (*teHndl)->destRect.top;
  3034.     else
  3035.         value = (*teHndl)->viewRect.left - (*teHndl)->destRect.left;
  3036.  
  3037.     if (value < 0)
  3038.         value = 0;
  3039.     if (value > max)
  3040.         value = max;
  3041.     if (value != oldValue) {
  3042.         if (front)
  3043.             SetControlValue(ctl, value);
  3044.         else
  3045.             (*ctl)->contrlValue = value;
  3046.     }
  3047. }
  3048.  
  3049.  
  3050.  
  3051. /*****************************************************************************/
  3052.  
  3053.  
  3054.  
  3055. Boolean    CTEUseTSMTE(void)
  3056. {
  3057.     return(gUseTSMTE = TSMTEAvailable());
  3058. }
  3059.  
  3060.  
  3061.  
  3062. /*****************************************************************************/
  3063.  
  3064.  
  3065.  
  3066. Boolean    TSMTEAvailable(void)
  3067. {
  3068.     long    response;
  3069.     
  3070.     if (Gestalt(kTSMTESignature, &response)) return(false);
  3071.  
  3072.     return((response & (1 << gestaltTSMTE)) != 0);
  3073. }
  3074.  
  3075.  
  3076.  
  3077. /*****************************************************************************/
  3078.  
  3079.  
  3080.  
  3081. static pascal void        TSMTEUpdateProc(TEHandle te, long fixLen, long inputAreaStart,
  3082.                                         long inputAreaEnd, long pinStart, long pinEnd, long refCon)
  3083. {
  3084. #ifndef __MWERKS__
  3085. #pragma unused (fixLen, inputAreaStart, inputAreaEnd, pinStart, pinEnd, refCon)
  3086. #endif
  3087.  
  3088.     CTEAdjustTEBottom(te);
  3089.     CTEAdjustScrollValues(te);
  3090. }
  3091.  
  3092.  
  3093.  
  3094. /*****************************************************************************/
  3095.  
  3096.  
  3097.  
  3098. Boolean    IsTECtl(ControlHandle ctl)
  3099. {
  3100.     if (ctl)
  3101.         if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gCDEF))
  3102.             return(true);
  3103.                 /* The handle may be locked, which means that the hi-bit
  3104.                 ** may be on, thus invalidating the compare.  Dereference the
  3105.                 ** handles to get rid of this possibility. */
  3106.  
  3107.     return(false);
  3108. }
  3109.  
  3110.  
  3111.  
  3112. /*****************************************************************************/
  3113.  
  3114.  
  3115.  
  3116. /* PPCClikLoop gets called by the TextEdit Manager from TEClick.
  3117. ** It calls the old, default click loop routine that scrolls the
  3118. ** text, and then calls our own Pascal routine that handles
  3119. ** tracking the scroll bars to follow along.  It does the same thing as the
  3120. ** 68K asm routine ASMTECLIKLOOP, but for PowerPC we don't have all the
  3121. ** register concerns. */
  3122.  
  3123. #ifdef powerc
  3124. static pascal Boolean    PPCClikLoop(TEPtr pTE)
  3125. {
  3126.     CallTEClickLoopProc(gDefaultClikLoopUPP, pTE);
  3127.         /* First call TextEdit's default ClikLoop routine */
  3128.  
  3129.     CTEClikLoop();        /* Now call our custom routine */
  3130.     return(true);
  3131. }
  3132.  
  3133. /*****/
  3134.  
  3135. /* PPCNoCaret does the samething as the 68K asm routine ASMNOCARET. Namely -- nothing. */
  3136. static pascal void    PPCNoCaret(const Rect *r, TEPtr pTE)
  3137. {
  3138. #ifndef __MWERKS__
  3139. #pragma unused (boundsRect, pTE)
  3140. #endif
  3141.     return;
  3142. }
  3143. #endif
  3144.  
  3145.  
  3146. #ifndef powerc
  3147. #ifdef __MWERKS__
  3148.  
  3149. asm pascal Boolean ASMTECLIKLOOP(void)
  3150. {
  3151.         movem.l    D1-D2/A1,-(SP)            /* D0 and A0 need not be saved. */
  3152.  
  3153.         movea.l    gDefaultClikLoopUPP,A0
  3154.         jsr    (A0)                        /* Execute TextEdit's default clikLoop. */
  3155.  
  3156.         movem.l    (SP)+,D1-D2/A1            /* Restore the world as it was. */
  3157.         movem.l    D1-D2/A1,-(SP)            /* D0 and A0 need not be saved. */
  3158.  
  3159.         jsr    CTEClikLoop
  3160.  
  3161.         movem.l    (SP)+,D1-D2/A1            /* Restore the world as it was. */
  3162.         moveq    #1,D0                    /* Clear the zero flag so TextEdit keeps going. */
  3163.         rts
  3164. }
  3165.  
  3166. asm pascal void ASMNOCARET(Rect *caretRect)
  3167. {
  3168.         move.l    (A7)+,D0
  3169.         rts
  3170. }
  3171.  
  3172. #endif
  3173. #endif
  3174.